bitkeeper revision 1.641 (3fcdb656yM6DlMdwk-janNkBhdceiQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 3 Dec 2003 10:09:26 +0000 (10:09 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 3 Dec 2003 10:09:26 +0000 (10:09 +0000)
Many files:
  new file
megaraid.c, Makefile, Rules.mk:
  New Fusion driver.

24 files changed:
.rootkeys
xen/Rules.mk
xen/drivers/Makefile
xen/drivers/message/fusion/Config.in [new file with mode: 0644]
xen/drivers/message/fusion/Makefile [new file with mode: 0644]
xen/drivers/message/fusion/isense.h [new file with mode: 0644]
xen/drivers/message/fusion/linux_compat.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/fc_log.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_cnfg.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_fc.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_history.txt [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_init.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_ioc.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_lan.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_raid.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_targ.h [new file with mode: 0644]
xen/drivers/message/fusion/lsi/mpi_type.h [new file with mode: 0644]
xen/drivers/message/fusion/mptbase.c [new file with mode: 0644]
xen/drivers/message/fusion/mptbase.h [new file with mode: 0644]
xen/drivers/message/fusion/mptscsih.c [new file with mode: 0644]
xen/drivers/message/fusion/mptscsih.h [new file with mode: 0644]
xen/drivers/message/fusion/scsi3.h [new file with mode: 0644]
xen/drivers/scsi/megaraid.c

index b3264c981129478943861a775d567bbc24164e8a..23ce80d11385207eb4a6b1d3b056a84d4b71cf97 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79bdkDY1bSOYkToP1Cc49VdBxg xen/drivers/ide/ide.c
 3ddb79bdPyAvT_WZTAFhaX0jp-yXSw xen/drivers/ide/ide_modes.h
 3e4a8d401aSwOzCScQXR3lsmNlAwUQ xen/drivers/ide/piix.c
+3fcdb64eEYjJwVTDdATmditDL6GreA xen/drivers/message/fusion/Config.in
+3fcdb64ee9dgWh8x0sR-le703mbyaQ xen/drivers/message/fusion/Makefile
+3fcdb64e_e-c5pG7ev4Ebpc1TSyqBA xen/drivers/message/fusion/isense.h
+3fcdb64ekZ3CRQVYOvtBY-jcdWLxFg xen/drivers/message/fusion/linux_compat.h
+3fcdb64e_ar-OB7FSvk8aIOQeETx-Q xen/drivers/message/fusion/lsi/fc_log.h
+3fcdb64eSDjgD3W3MypMOae50Fe4BA xen/drivers/message/fusion/lsi/mpi.h
+3fcdb64e9iLTo9Etbdxrr_dC-1bb5g xen/drivers/message/fusion/lsi/mpi_cnfg.h
+3fcdb64egl5jNkfKyC7Co6NNNsfY4w xen/drivers/message/fusion/lsi/mpi_fc.h
+3fcdb64edETmgJSw8KhkrQgyY67BTA xen/drivers/message/fusion/lsi/mpi_history.txt
+3fcdb64eHxLXhIqEfYi8_UPf4j7Kng xen/drivers/message/fusion/lsi/mpi_init.h
+3fcdb64fG8Mm8Jt4Il-jsVcKTfRTpg xen/drivers/message/fusion/lsi/mpi_ioc.h
+3fcdb64fjt9nuJga7t5dRK1-FCrURQ xen/drivers/message/fusion/lsi/mpi_lan.h
+3fcdb64fnnYbvcLibeLTNR81zMi8Lw xen/drivers/message/fusion/lsi/mpi_raid.h
+3fcdb64fpRM8NpPlaagM3dQ1jW3YNQ xen/drivers/message/fusion/lsi/mpi_targ.h
+3fcdb64fXgeuSY_4Uy_OWSyjWlwnaQ xen/drivers/message/fusion/lsi/mpi_type.h
+3fcdb64fQjcOsOCcCMQSBgA0kuttPA xen/drivers/message/fusion/mptbase.c
+3fcdb64fz22QsBDCmRylGcrYz2X2YQ xen/drivers/message/fusion/mptbase.h
+3fcdb64fqClM55cDs-jlCSJ7fhqmqg xen/drivers/message/fusion/mptscsih.c
+3fcdb64fTVgpQj9UQw5aHN_eUHlzGQ xen/drivers/message/fusion/mptscsih.h
+3fcdb64fl9djvIFAYQozgMVDUNPIkQ xen/drivers/message/fusion/scsi3.h
 3ddb79bfMlOcWUwjtg6oMYhGySHDDw xen/drivers/net/3c59x.c
 3ddb79c0tWiE8xIFHszxipeVCGKTSA xen/drivers/net/Makefile
 3f0c4247730LYUgz3p5ziYqy-s_glw xen/drivers/net/SUPPORTED_CARDS
index a34a740f7689e9fcb0609fa80490be0144dd8f18..82d459f933e8875e011f0a0155a5d8cebefc5b9c 100644 (file)
@@ -23,6 +23,7 @@ ALL_OBJS += $(BASEDIR)/drivers/block/driver.o
 ALL_OBJS += $(BASEDIR)/drivers/cdrom/driver.o
 ALL_OBJS += $(BASEDIR)/drivers/ide/driver.o
 ALL_OBJS += $(BASEDIR)/drivers/scsi/driver.o
+ALL_OBJS += $(BASEDIR)/drivers/message/fusion/driver.o
 ALL_OBJS += $(BASEDIR)/arch/$(ARCH)/arch.o
 
 HOSTCC     = gcc
index 814ed909d84b3b5a69a4b064bab86efd225d5030..2d969e41be1705341cd2d0d8171f6753a0469fdf 100644 (file)
@@ -7,6 +7,7 @@ default:
        $(MAKE) -C cdrom
        $(MAKE) -C ide
        $(MAKE) -C scsi
+       $(MAKE) -C message/fusion
 
 clean:
        $(MAKE) -C char clean
@@ -16,3 +17,4 @@ clean:
        $(MAKE) -C cdrom clean
        $(MAKE) -C ide clean
        $(MAKE) -C scsi clean
+       $(MAKE) -C message/fusion clean
diff --git a/xen/drivers/message/fusion/Config.in b/xen/drivers/message/fusion/Config.in
new file mode 100644 (file)
index 0000000..3927420
--- /dev/null
@@ -0,0 +1,38 @@
+mainmenu_option next_comment
+comment 'Fusion MPT device support'
+
+dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $CONFIG_BLK_DEV_SD
+
+if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then
+
+  if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then
+    define_bool CONFIG_FUSION_BOOT y
+  else
+    define_bool CONFIG_FUSION_BOOT n
+  fi
+  int  "  Maximum number of scatter gather entries" CONFIG_FUSION_MAX_SGE 40 
+
+  if [ "$CONFIG_MODULES" = "y" ]; then
+    #  How can we force these options to module or nothing?
+    dep_tristate "  Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m
+    dep_tristate "  Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m
+  fi
+
+  dep_tristate "  Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET
+  if [ "$CONFIG_FUSION_LAN" != "n" ]; then
+    define_bool CONFIG_NET_FC y
+  fi
+
+else
+
+  define_bool CONFIG_FUSION_BOOT n
+  # These <should> be define_tristate, but we leave them define_bool
+  # for backward compatibility with pre-linux-2.2.15 kernels.
+  # (Bugzilla:fibrebugs, #384)
+  define_bool CONFIG_FUSION_ISENSE n
+  define_bool CONFIG_FUSION_CTL n
+  define_bool CONFIG_FUSION_LAN n
+
+fi
+
+endmenu
diff --git a/xen/drivers/message/fusion/Makefile b/xen/drivers/message/fusion/Makefile
new file mode 100644 (file)
index 0000000..3e30f33
--- /dev/null
@@ -0,0 +1,11 @@
+
+include $(BASEDIR)/Rules.mk
+
+# naive OBJS rule gets link order wrong
+FUSIONOBJS := mptbase.o mptscsih.o
+
+default: $(OBJS)
+       $(LD) -r -o driver.o $(FUSIONOBJS)
+
+clean:
+       rm -f *.o *~ core
diff --git a/xen/drivers/message/fusion/isense.h b/xen/drivers/message/fusion/isense.h
new file mode 100644 (file)
index 0000000..e1ce503
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef ISENSE_H_INCLUDED
+#define ISENSE_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifdef __KERNEL__
+#include <linux/types.h>               /* needed for u8, etc. */
+#include <linux/string.h>              /* needed for strcat   */
+#include <linux/kernel.h>              /* needed for sprintf  */
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+#include "scsi3.h"                     /* needed for all things SCSI */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Defines and typedefs...
+ */
+
+#ifdef __KERNEL__
+#define PrintF(x) printk x
+#else
+#define PrintF(x) printf x
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define RETRY_STATUS  ((int) 1)
+#define PUT_STATUS    ((int) 0)
+
+/*
+ *    A generic structure to hold info about IO request that caused
+ *    a Request Sense to be performed, and the resulting Sense Data.
+ */
+typedef struct IO_Info
+{
+    char *DevIDStr;   /* String of chars which identifies the device.       */
+    u8   *cdbPtr;     /* Pointer (Virtual/Logical addr) to CDB bytes of
+                           IO request that caused ContAllegianceCond.       */
+    u8   *sensePtr;   /* Pointer (Virtual/Logical addr) to Sense Data
+                           returned by Request Sense operation.             */
+    u8   *dataPtr;    /* Pointer (Virtual/Logical addr) to Data buffer
+                           of IO request caused ContAllegianceCondition.    */
+    u8   *inqPtr;     /* Pointer (Virtual/Logical addr) to Inquiry Data for
+                           IO *Device* that caused ContAllegianceCondition. */
+    u8    SCSIStatus; /* SCSI status byte of IO request that caused
+                           Contingent Allegiance Condition.                 */
+    u8    DoDisplay;  /* Shall we display any messages?                     */
+    u16   rsvd_align1;
+    u32   ComplCode;  /* Four-byte OS-dependent completion code.            */
+    u32   NotifyL;    /* Four-byte OS-dependent notification field.         */
+} IO_Info_t;
+
+/*
+ *  SCSI Additional Sense Code and Additional Sense Code Qualifier table.
+ */
+typedef struct ASCQ_Table
+{
+    u8     ASC;
+    u8     ASCQ;
+    char  *DevTypes;
+    char  *Description;
+} ASCQ_Table_t;
+
+#if 0
+/*
+ *  SCSI Opcodes table.
+ */
+typedef struct SCSI_OPS_Table
+{
+    u8     OpCode;
+    char  *DevTypes;
+    char  *ScsiCmndStr;
+} SCSI_OPS_Table_t;
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public entry point prototypes
+ */
+
+/* in scsiherr.c, needed by mptscsih.c */
+extern int      mpt_ScsiHost_ErrorReport(IO_Info_t *ioop);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
diff --git a/xen/drivers/message/fusion/linux_compat.h b/xen/drivers/message/fusion/linux_compat.h
new file mode 100644 (file)
index 0000000..1a79855
--- /dev/null
@@ -0,0 +1,295 @@
+/* drivers/message/fusion/linux_compat.h */
+
+#ifndef FUSION_LINUX_COMPAT_H
+#define FUSION_LINUX_COMPAT_H
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef rwlock_init
+#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#define SET_NICE(current,x)    do {(current)->nice = (x);} while (0)
+#else
+#define SET_NICE(current,x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#define pci_enable_device(pdev)        (0)
+#define SCSI_DATA_UNKNOWN      0
+#define SCSI_DATA_WRITE                1
+#define SCSI_DATA_READ         2
+#define SCSI_DATA_NONE         3
+#endif
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+#define pci_set_dma_mask(pdev, mask)   (0)
+#define scsi_set_pci_device(sh, pdev)  (0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#      if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+               typedef unsigned int dma_addr_t;
+#      endif
+#else
+#      if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42)
+               typedef unsigned int dma_addr_t;
+#      endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* This block snipped from lk-2.2.18/include/linux/init.h { */
+/*
+ * Used for initialization calls..
+ */
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init_call    __attribute__ ((unused,__section__ (".initcall.init")))
+#define __exit_call    __attribute__ ((unused,__section__ (".exitcall.exit")))
+
+extern initcall_t __initcall_start, __initcall_end;
+
+#define __initcall(fn)                                                         \
+       static initcall_t __initcall_##fn __init_call = fn
+#define __exitcall(fn)                                                         \
+       static exitcall_t __exitcall_##fn __exit_call = fn
+
+#ifdef MODULE
+/* These macros create a dummy inline: gcc 2.9x does not count alias
+ as usage, hence the `unused function' warning when __init functions
+ are declared static. We use the dummy __*_module_inline functions
+ both to kill the warning and check the type of the init/cleanup
+ function. */
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+#define module_init(x) \
+       int init_module(void) __attribute__((alias(#x))); \
+       static inline __init_module_func_t __init_module_inline(void) \
+       { return x; }
+#define module_exit(x) \
+       void cleanup_module(void) __attribute__((alias(#x))); \
+       static inline __cleanup_module_func_t __cleanup_module_inline(void) \
+       { return x; }
+
+#else
+#define module_init(x) __initcall(x);
+#define module_exit(x) __exitcall(x);
+#endif
+/* } block snipped from lk-2.2.18/include/linux/init.h */
+
+/* This block snipped from lk-2.2.18/include/linux/sched.h { */
+/*
+ * Used prior to schedule_timeout calls..
+ */
+#define __set_current_state(state_value)       do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value)         do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value)         __set_current_state(state_value)
+#endif
+/* } block snipped from lk-2.2.18/include/linux/sched.h */
+
+/* procfs compat stuff... */
+#define proc_mkdir(x,y)                        create_proc_entry(x, S_IFDIR, y)
+
+/* MUTEX compat stuff... */
+#define DECLARE_MUTEX(name)            struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)     struct semaphore name=MUTEX_LOCKED
+#define init_MUTEX(x)                  *(x)=MUTEX
+#define init_MUTEX_LOCKED(x)           *(x)=MUTEX_LOCKED
+
+/* Wait queues. */
+#define DECLARE_WAIT_QUEUE_HEAD(name)  \
+       struct wait_queue * (name) = NULL
+#define DECLARE_WAITQUEUE(name, task)  \
+       struct wait_queue (name) = { (task), NULL }
+
+#if defined(__sparc__) && defined(__sparc_v9__)
+/* The sparc64 ioremap implementation is wrong in 2.2.x,
+ * but fixing it would break all of the drivers which
+ * workaround it.  Fixed in 2.3.x onward. -DaveM
+ */
+#define ARCH_IOREMAP(base)     ((unsigned long) (base))
+#else
+#define ARCH_IOREMAP(base)     ioremap(base)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#else          /* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */
+
+/* No ioremap bugs in >2.3.x kernels. */
+#define ARCH_IOREMAP(base)     ioremap(base)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif         /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
+
+
+/*
+ * Inclined to use:
+ *   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+ * here, but MODULE_LICENSE defined in 2.4.9-6 and 2.4.9-13
+ * breaks the rule:-(
+ */
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(license)
+#endif
+
+
+/* PCI/driver subsystem { */
+/* SAE: Why not just use Linux's PCI stuff */
+#if XENO_KILLED
+/*#ifndef pci_for_each_dev*/
+#define pci_for_each_dev(dev)          for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next)
+#define pci_peek_next_dev(dev)         ((dev)->next ? (dev)->next : NULL)
+#define DEVICE_COUNT_RESOURCE           6
+#define PCI_BASEADDR_FLAGS(idx)         base_address[idx]
+#define PCI_BASEADDR_START(idx)         base_address[idx] & ~0xFUL
+/*
+ * We have to keep track of the original value using
+ * a temporary, and not by just sticking pdev->base_address[x]
+ * back.  pdev->base_address[x] is an opaque cookie that can
+ * be used by the PCI implementation on a given Linux port
+ * for any purpose. -DaveM
+ */
+#define PCI_BASEADDR_SIZE(__pdev, __idx) \
+({     unsigned int size, tmp; \
+       pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \
+       pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \
+       pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \
+       pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \
+       (4 - size); \
+})
+#else
+/* SAE: Is Linux's PCI stuff not good enough? */
+#if XENO_KILLED
+
+#define pci_peek_next_dev(dev)         ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL)
+#define PCI_BASEADDR_FLAGS(idx)         resource[idx].flags
+#define PCI_BASEADDR_START(idx)         resource[idx].start
+#define PCI_BASEADDR_SIZE(dev,idx)      (dev)->resource[idx].end - (dev)->resource[idx].start + 1
+
+#endif
+#endif         /* } ifndef pci_for_each_dev */
+
+
+/* Compatability for the 2.3.x PCI DMA API. */
+/* SAE: No need for this */
+#if XENO_KILLED
+/*#ifndef PCI_DMA_BIDIRECTIONAL*/
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define PCI_DMA_BIDIRECTIONAL  0
+#define PCI_DMA_TODEVICE       1
+#define PCI_DMA_FROMDEVICE     2
+#define PCI_DMA_NONE           3
+
+#ifdef __KERNEL__
+#include <asm/page.h>
+/* Pure 2^n version of get_order */
+static __inline__ int __get_order(unsigned long size)
+{
+       int order;
+
+       size = (size-1) >> (PAGE_SHIFT-1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+       return order;
+}
+#endif
+
+#define pci_alloc_consistent(hwdev, size, dma_handle) \
+({     void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \
+       if (__ret != NULL) { \
+               memset(__ret, 0, size); \
+               *(dma_handle) = virt_to_bus(__ret); \
+       } \
+       __ret; \
+})
+
+#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \
+       free_pages((unsigned long)vaddr, __get_order(size))
+
+#define pci_map_single(hwdev, ptr, size, direction) \
+       virt_to_bus(ptr);
+
+#define pci_unmap_single(hwdev, dma_addr, size, direction) \
+       do { /* Nothing to do */ } while (0)
+
+#define pci_map_sg(hwdev, sg, nents, direction)        (nents)
+#define pci_unmap_sg(hwdev, sg, nents, direction) \
+       do { /* Nothing to do */ } while(0)
+
+#define sg_dma_address(sg)     (virt_to_bus((sg)->address))
+#define sg_dma_len(sg)         ((sg)->length)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* PCI_DMA_BIDIRECTIONAL */
+
+/*
+ *  With the new command queuing code in the SCSI mid-layer we no longer have
+ *  to hold the io_request_lock spin lock when calling the scsi_done routine.
+ *  For now we only do this with the 2.5.1 kernel or newer.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+        #define MPT_HOST_LOCK(flags)
+        #define MPT_HOST_UNLOCK(flags)
+#else
+        #define MPT_HOST_LOCK(flags) \
+                spin_lock_irqsave(&io_request_lock, flags)
+        #define MPT_HOST_UNLOCK(flags) \
+                spin_unlock_irqrestore(&io_request_lock, flags)
+#endif
+
+/*
+ *  We use our new error handling code if the kernel version is 2.4.18 or newer.
+ *  Remark: 5/5/03 use old EH code with 2.4 kernels as it runs in a background thread
+ *  2.4 kernels choke on a call to schedule via eh thread.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+        #define MPT_SCSI_USE_NEW_EH
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#define mpt_work_struct work_struct
+#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
+#else
+#define mpt_work_struct tq_struct
+#define MPT_INIT_WORK(_task, _func, _data) \
+({     (_task)->sync = 0; \
+       (_task)->routine = (_func); \
+       (_task)->data = (void *) (_data); \
+})
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+#define mptscsih_sync_irq(_irq) synchronize_irq(_irq)
+#else
+#define mptscsih_sync_irq(_irq) synchronize_irq()
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,58)
+#define mpt_inc_use_count()
+#define mpt_dec_use_count()
+#else
+#define mpt_inc_use_count() MOD_INC_USE_COUNT
+#define mpt_dec_use_count() MOD_DEC_USE_COUNT
+#endif
+
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif /* _LINUX_COMPAT_H */
+
diff --git a/xen/drivers/message/fusion/lsi/fc_log.h b/xen/drivers/message/fusion/lsi/fc_log.h
new file mode 100644 (file)
index 0000000..dc98d46
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *
+ *  NAME:           fc_log.h
+ *  SUMMARY:        MPI IocLogInfo definitions for the SYMFC9xx chips
+ *  DESCRIPTION:    Contains the enumerated list of values that may be returned
+ *                  in the IOCLogInfo field of a MPI Default Reply Message.
+ *
+ *  CREATION DATE:  6/02/2000
+ *  ID:             $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $
+ */
+
+
+/*
+ * MpiIocLogInfo_t enum
+ *
+ * These 32 bit values are used in the IOCLogInfo field of the MPI reply
+ * messages.
+ * The value is 0xabcccccc where
+ *          a = The type of log info as per the MPI spec. Since these codes are
+ *              all for Fibre Channel this value will always be 2.
+ *          b = Specifies a subclass of the firmware where
+ *                  0 = FCP Initiator
+ *                  1 = FCP Target
+ *                  2 = LAN
+ *                  3 = MPI Message Layer
+ *                  4 = FC Link
+ *                  5 = Context Manager
+ *                  6 = Invalid Field Offset
+ *                  7 = State Change Info
+ *                  all others are reserved for future use
+ *          c = A specific value within the subclass.
+ *
+ * NOTE: Any new values should be added to the end of each subclass so that the
+ *       codes remain consistent across firmware releases.
+ */
+typedef enum _MpiIocLogInfoFc
+{
+    MPI_IOCLOGINFO_FC_INIT_BASE                     = 0x20000000,
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME   = 0x20000003, /* Bad Rx Frame, bad end of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN           = 0x20000004, /* Bad Rx Frame, overrun */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER           = 0x20000005, /* Other errors caught by IOC which require retries */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD       = 0x20000006, /* Main processor could not initialize sub-processor */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN         = 0x20000007, /* Scatter Gather overrun  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS      = 0x20000008, /* Receiver detected context mismatch via invalid header */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE       = 0x2000000A, /* Link failure occurred  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT         = 0x2000000B, /* Transmitter timeout error */
+
+    MPI_IOCLOGINFO_FC_TARGET_BASE                   = 0x21000000,
+    MPI_IOCLOGINFO_FC_TARGET_NO_PDISC               = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
+    MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN               = 0x21000002, /* not sent because we are not logged in to the remote node */
+    MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP     = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP     = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA      = 0x21000005, /* Data In, Auto Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP     = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP     = 0x21000007, /* Auto-response after a write not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP     = 0x21000008, /* Data In, No Response, not completed due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA      = 0x21000009, /* Data In, No Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP     = 0x2100000a, /* Manual Response not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3             = 0x2100000b, /* not sent because remote node does not support Class 3 */
+    MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID        = 0x2100000c, /* not sent because login to remote node not validated */
+    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound queue after a logout */
+    MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN    = 0x2100000f, /* cleared waiting for data after a logout */
+
+    MPI_IOCLOGINFO_FC_LAN_BASE                      = 0x22000000,
+    MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING         = 0x22000001, /* Transaction Context Sgl Missing */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE         = 0x22000002, /* Transaction Context found before an EOB */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET        = 0x22000003, /* Transaction Context value has reserved bits set */
+    MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG            = 0x22000004, /* Invalid SGL Flags */
+
+    MPI_IOCLOGINFO_FC_MSG_BASE                      = 0x23000000,
+
+    MPI_IOCLOGINFO_FC_LINK_BASE                     = 0x24000000,
+    MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT        = 0x24000001, /* Loop initialization timed out */
+    MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED      = 0x24000002, /* Another system controller already initialized the loop */
+    MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED     = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
+    MPI_IOCLOGINFO_FC_LINK_CRC_ERROR                = 0x24000004, /* CRC check detected error on received frame */
+
+    MPI_IOCLOGINFO_FC_CTX_BASE                      = 0x25000000,
+
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET     = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET      = 0x26ffffff,
+
+    MPI_IOCLOGINFO_FC_STATE_CHANGE                  = 0x27000000  /* The lower 24 bits give additional information concerning state change */
+
+} MpiIocLogInfoFc_t;
diff --git a/xen/drivers/message/fusion/lsi/mpi.h b/xen/drivers/message/fusion/lsi/mpi.h
new file mode 100644 (file)
index 0000000..0a43905
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI.H
+ *          Title:  MPI Message independent structures and definitions
+ *  Creation Date:  July 27, 2000
+ *
+ *    MPI.H Version:  01.02.07
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ *  06-06-00  01.00.01  Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ *  06-22-00  01.00.02  Added MPI_IOCSTATUS_LAN_ definitions.
+ *                      Removed LAN_SUSPEND function definition.
+ *                      Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ *  06-30-00  01.00.03  Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ *                      Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ *  07-27-00  01.00.04  Added MPI_FAULT_ definitions.
+ *                      Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ *                      Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ *                      Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *  12-04-00  01.01.02  Added new function codes.
+ *  01-09-01  01.01.03  Added more definitions to the system interface section
+ *                      Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ *  01-25-01  01.01.04  Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *                      Fixed value for MPI_DIAG_RW_ENABLE.
+ *                      Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ *                      MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ *                      Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ *  02-27-01  01.01.06  Removed MPI_HOST_INDEX_REGISTER define.
+ *                      Added function codes for RAID.
+ *  04-09-01  01.01.07  Added alternate define for MPI_DOORBELL_ACTIVE,
+ *                      MPI_DOORBELL_USED, to better match the spec.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Changed MPI_VERSION_MINOR from 0x01 to 0x02.
+ *                      Added define MPI_FUNCTION_TOOLBOX.
+ *  09-28-01  01.02.02  New function code MPI_SCSI_ENCLOSURE_PROCESSOR.
+ *  11-01-01  01.02.03  Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR.
+ *  03-14-02  01.02.04  Added MPI_HEADER_VERSION_ defines.
+ *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
+ *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
+ *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_H
+#define MPI_H
+
+
+/*****************************************************************************
+*
+*        M P I    V e r s i o n    D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_VERSION_MAJOR                   (0x01)
+#define MPI_VERSION_MINOR                   (0x02)
+#define MPI_VERSION_MAJOR_MASK              (0xFF00)
+#define MPI_VERSION_MAJOR_SHIFT             (8)
+#define MPI_VERSION_MINOR_MASK              (0x00FF)
+#define MPI_VERSION_MINOR_SHIFT             (0)
+#define MPI_VERSION ((MPI_VERSION_MAJOR << MPI_VERSION_MAJOR_SHIFT) |   \
+                                      MPI_VERSION_MINOR)
+
+#define MPI_VERSION_01_00                   (0x0100)
+#define MPI_VERSION_01_01                   (0x0101)
+#define MPI_VERSION_01_02                   (0x0102)
+/* Note: The major versions of 0xe0 through 0xff are reserved */
+
+/* versioning for this MPI header set */
+#define MPI_HEADER_VERSION_UNIT             (0x09)
+#define MPI_HEADER_VERSION_DEV              (0x00)
+#define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
+#define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
+#define MPI_HEADER_VERSION_DEV_MASK         (0x00FF)
+#define MPI_HEADER_VERSION_DEV_SHIFT        (0)
+#define MPI_HEADER_VERSION ((MPI_HEADER_VERSION_UNIT << 8) | MPI_HEADER_VERSION_DEV)
+
+/*****************************************************************************
+*
+*        I O C    S t a t e    D e f i n i t i o n s
+*
+*****************************************************************************/
+
+#define MPI_IOC_STATE_RESET                 (0x00000000)
+#define MPI_IOC_STATE_READY                 (0x10000000)
+#define MPI_IOC_STATE_OPERATIONAL           (0x20000000)
+#define MPI_IOC_STATE_FAULT                 (0x40000000)
+
+#define MPI_IOC_STATE_MASK                  (0xF0000000)
+#define MPI_IOC_STATE_SHIFT                 (28)
+
+/* Fault state codes (product independent range 0x8000-0xFFFF) */
+
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_PARITY_ERROR  (0x8111)
+#define MPI_FAULT_REQUEST_MESSAGE_PCI_BUS_FAULT     (0x8112)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_PARITY_ERROR    (0x8113)
+#define MPI_FAULT_REPLY_MESSAGE_PCI_BUS_FAULT       (0x8114)
+#define MPI_FAULT_DATA_SEND_PCI_PARITY_ERROR        (0x8115)
+#define MPI_FAULT_DATA_SEND_PCI_BUS_FAULT           (0x8116)
+#define MPI_FAULT_DATA_RECEIVE_PCI_PARITY_ERROR     (0x8117)
+#define MPI_FAULT_DATA_RECEIVE_PCI_BUS_FAULT        (0x8118)
+
+
+/*****************************************************************************
+*
+*        P C I    S y s t e m    I n t e r f a c e    R e g i s t e r s
+*
+*****************************************************************************/
+
+/* S y s t e m    D o o r b e l l */
+#define MPI_DOORBELL_OFFSET                 (0x00000000)
+#define MPI_DOORBELL_ACTIVE                 (0x08000000) /* DoorbellUsed */
+#define MPI_DOORBELL_USED                   (MPI_DOORBELL_ACTIVE)
+#define MPI_DOORBELL_ACTIVE_SHIFT           (27)
+#define MPI_DOORBELL_WHO_INIT_MASK          (0x07000000)
+#define MPI_DOORBELL_WHO_INIT_SHIFT         (24)
+#define MPI_DOORBELL_FUNCTION_MASK          (0xFF000000)
+#define MPI_DOORBELL_FUNCTION_SHIFT         (24)
+#define MPI_DOORBELL_ADD_DWORDS_MASK        (0x00FF0000)
+#define MPI_DOORBELL_ADD_DWORDS_SHIFT       (16)
+#define MPI_DOORBELL_DATA_MASK              (0x0000FFFF)
+
+
+#define MPI_WRITE_SEQUENCE_OFFSET           (0x00000004)
+#define MPI_WRSEQ_KEY_VALUE_MASK            (0x0000000F)
+#define MPI_WRSEQ_1ST_KEY_VALUE             (0x04)
+#define MPI_WRSEQ_2ND_KEY_VALUE             (0x0B)
+#define MPI_WRSEQ_3RD_KEY_VALUE             (0x02)
+#define MPI_WRSEQ_4TH_KEY_VALUE             (0x07)
+#define MPI_WRSEQ_5TH_KEY_VALUE             (0x0D)
+
+#define MPI_DIAGNOSTIC_OFFSET               (0x00000008)
+#define MPI_DIAG_CLEAR_FLASH_BAD_SIG        (0x00000400)
+#define MPI_DIAG_PREVENT_IOC_BOOT           (0x00000200)
+#define MPI_DIAG_DRWE                       (0x00000080)
+#define MPI_DIAG_FLASH_BAD_SIG              (0x00000040)
+#define MPI_DIAG_RESET_HISTORY              (0x00000020)
+#define MPI_DIAG_RW_ENABLE                  (0x00000010)
+#define MPI_DIAG_RESET_ADAPTER              (0x00000004)
+#define MPI_DIAG_DISABLE_ARM                (0x00000002)
+#define MPI_DIAG_MEM_ENABLE                 (0x00000001)
+
+#define MPI_TEST_BASE_ADDRESS_OFFSET        (0x0000000C)
+
+#define MPI_DIAG_RW_DATA_OFFSET             (0x00000010)
+
+#define MPI_DIAG_RW_ADDRESS_OFFSET          (0x00000014)
+
+#define MPI_HOST_INTERRUPT_STATUS_OFFSET    (0x00000030)
+#define MPI_HIS_IOP_DOORBELL_STATUS         (0x80000000)
+#define MPI_HIS_REPLY_MESSAGE_INTERRUPT     (0x00000008)
+#define MPI_HIS_DOORBELL_INTERRUPT          (0x00000001)
+
+#define MPI_HOST_INTERRUPT_MASK_OFFSET      (0x00000034)
+#define MPI_HIM_RIM                         (0x00000008)
+#define MPI_HIM_DIM                         (0x00000001)
+
+#define MPI_REQUEST_QUEUE_OFFSET            (0x00000040)
+#define MPI_REQUEST_POST_FIFO_OFFSET        (0x00000040)
+
+#define MPI_REPLY_QUEUE_OFFSET              (0x00000044)
+#define MPI_REPLY_POST_FIFO_OFFSET          (0x00000044)
+#define MPI_REPLY_FREE_FIFO_OFFSET          (0x00000044)
+
+
+
+/*****************************************************************************
+*
+*        M e s s a g e    F r a m e    D e s c r i p t o r s
+*
+*****************************************************************************/
+
+#define MPI_REQ_MF_DESCRIPTOR_NB_MASK       (0x00000003)
+#define MPI_REQ_MF_DESCRIPTOR_F_BIT         (0x00000004)
+#define MPI_REQ_MF_DESCRIPTOR_ADDRESS_MASK  (0xFFFFFFF8)
+
+#define MPI_ADDRESS_REPLY_A_BIT             (0x80000000)
+#define MPI_ADDRESS_REPLY_ADDRESS_MASK      (0x7FFFFFFF)
+
+#define MPI_CONTEXT_REPLY_A_BIT             (0x80000000)
+#define MPI_CONTEXT_REPLY_TYPE_MASK         (0x60000000)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_INIT    (0x00)
+#define MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET  (0x01)
+#define MPI_CONTEXT_REPLY_TYPE_LAN          (0x02)
+#define MPI_CONTEXT_REPLY_TYPE_SHIFT        (29)
+#define MPI_CONTEXT_REPLY_CONTEXT_MASK      (0x1FFFFFFF)
+
+
+/****************************************************************************/
+/* Context Reply macros                                                     */
+/****************************************************************************/
+
+#define MPI_GET_CONTEXT_REPLY_TYPE(x)  (((x) & MPI_CONTEXT_REPLY_TYPE_MASK) \
+                                          >> MPI_CONTEXT_REPLY_TYPE_SHIFT)
+
+#define MPI_SET_CONTEXT_REPLY_TYPE(x, typ)                                  \
+            ((x) = ((x) & ~MPI_CONTEXT_REPLY_TYPE_MASK) |                   \
+                            (((typ) << MPI_CONTEXT_REPLY_TYPE_SHIFT) &      \
+                                        MPI_CONTEXT_REPLY_TYPE_MASK))
+
+
+/*****************************************************************************
+*
+*        M e s s a g e    F u n c t i o n s
+*              0x80 -> 0x8F reserved for private message use per product
+*
+*
+*****************************************************************************/
+
+#define MPI_FUNCTION_SCSI_IO_REQUEST                (0x00)
+#define MPI_FUNCTION_SCSI_TASK_MGMT                 (0x01)
+#define MPI_FUNCTION_IOC_INIT                       (0x02)
+#define MPI_FUNCTION_IOC_FACTS                      (0x03)
+#define MPI_FUNCTION_CONFIG                         (0x04)
+#define MPI_FUNCTION_PORT_FACTS                     (0x05)
+#define MPI_FUNCTION_PORT_ENABLE                    (0x06)
+#define MPI_FUNCTION_EVENT_NOTIFICATION             (0x07)
+#define MPI_FUNCTION_EVENT_ACK                      (0x08)
+#define MPI_FUNCTION_FW_DOWNLOAD                    (0x09)
+#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST         (0x0A)
+#define MPI_FUNCTION_TARGET_ASSIST                  (0x0B)
+#define MPI_FUNCTION_TARGET_STATUS_SEND             (0x0C)
+#define MPI_FUNCTION_TARGET_MODE_ABORT              (0x0D)
+#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC   (0x0E) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC        (0x0F) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC    (0x10) /* obsolete name */
+#define MPI_FUNCTION_TARGET_FC_ABORT                (0x11) /* obsolete name */
+#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST          (0x0E)
+#define MPI_FUNCTION_FC_LINK_SRVC_RSP               (0x0F)
+#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND           (0x10)
+#define MPI_FUNCTION_FC_ABORT                       (0x11)
+#define MPI_FUNCTION_FW_UPLOAD                      (0x12)
+#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND       (0x13)
+#define MPI_FUNCTION_FC_PRIMITIVE_SEND              (0x14)
+
+#define MPI_FUNCTION_RAID_ACTION                    (0x15)
+#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH       (0x16)
+
+#define MPI_FUNCTION_TOOLBOX                        (0x17)
+
+#define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR       (0x18)
+
+#define MPI_FUNCTION_MAILBOX                        (0x19)
+
+#define MPI_FUNCTION_LAN_SEND                       (0x20)
+#define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
+#define MPI_FUNCTION_LAN_RESET                      (0x22)
+
+#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET         (0x40)
+#define MPI_FUNCTION_IO_UNIT_RESET                  (0x41)
+#define MPI_FUNCTION_HANDSHAKE                      (0x42)
+#define MPI_FUNCTION_REPLY_FRAME_REMOVAL            (0x43)
+
+
+
+/*****************************************************************************
+*
+*        S c a t t e r    G a t h e r    E l e m e n t s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Simple element structures                                               */
+/****************************************************************************/
+
+typedef struct _SGE_SIMPLE32
+{
+    U32                     FlagsLength;
+    U32                     Address;
+} SGE_SIMPLE32, MPI_POINTER PTR_SGE_SIMPLE32,
+  SGESimple32_t, MPI_POINTER pSGESimple32_t;
+
+typedef struct _SGE_SIMPLE64
+{
+    U32                     FlagsLength;
+    U64                     Address;
+} SGE_SIMPLE64, MPI_POINTER PTR_SGE_SIMPLE64,
+  SGESimple64_t, MPI_POINTER pSGESimple64_t;
+
+typedef struct _SGE_SIMPLE_UNION
+{
+    U32                     FlagsLength;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    }u;
+} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t,
+  SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION;
+
+/****************************************************************************/
+/*  Chain element structures                                                */
+/****************************************************************************/
+
+typedef struct _SGE_CHAIN32
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U32                     Address;
+} SGE_CHAIN32, MPI_POINTER PTR_SGE_CHAIN32,
+  SGEChain32_t, MPI_POINTER pSGEChain32_t;
+
+typedef struct _SGE_CHAIN64
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    U64                     Address;
+} SGE_CHAIN64, MPI_POINTER PTR_SGE_CHAIN64,
+  SGEChain64_t, MPI_POINTER pSGEChain64_t;
+
+typedef struct _SGE_CHAIN_UNION
+{
+    U16                     Length;
+    U8                      NextChainOffset;
+    U8                      Flags;
+    union
+    {
+        U32                 Address32;
+        U64                 Address64;
+    }u;
+} SGE_CHAIN_UNION, MPI_POINTER PTR_SGE_CHAIN_UNION,
+  SGEChainUnion_t, MPI_POINTER pSGEChainUnion_t;
+
+/****************************************************************************/
+/*  Transaction Context element                                             */
+/****************************************************************************/
+
+typedef struct _SGE_TRANSACTION32
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[1];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION32, MPI_POINTER PTR_SGE_TRANSACTION32,
+  SGETransaction32_t, MPI_POINTER pSGETransaction32_t;
+
+typedef struct _SGE_TRANSACTION64
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[2];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION64, MPI_POINTER PTR_SGE_TRANSACTION64,
+  SGETransaction64_t, MPI_POINTER pSGETransaction64_t;
+
+typedef struct _SGE_TRANSACTION96
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[3];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION96, MPI_POINTER PTR_SGE_TRANSACTION96,
+  SGETransaction96_t, MPI_POINTER pSGETransaction96_t;
+
+typedef struct _SGE_TRANSACTION128
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    U32                     TransactionContext[4];
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION128, MPI_POINTER PTR_SGE_TRANSACTION128,
+  SGETransaction_t128, MPI_POINTER pSGETransaction_t128;
+
+typedef struct _SGE_TRANSACTION_UNION
+{
+    U8                      Reserved;
+    U8                      ContextSize;
+    U8                      DetailsLength;
+    U8                      Flags;
+    union
+    {
+        U32                 TransactionContext32[1];
+        U32                 TransactionContext64[2];
+        U32                 TransactionContext96[3];
+        U32                 TransactionContext128[4];
+    }u;
+    U32                     TransactionDetails[1];
+} SGE_TRANSACTION_UNION, MPI_POINTER PTR_SGE_TRANSACTION_UNION,
+  SGETransactionUnion_t, MPI_POINTER pSGETransactionUnion_t;
+
+
+/****************************************************************************/
+/*  SGE IO types union  for IO SGL's                                        */
+/****************************************************************************/
+
+typedef struct _SGE_IO_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION    Simple;
+        SGE_CHAIN_UNION     Chain;
+    } u;
+} SGE_IO_UNION, MPI_POINTER PTR_SGE_IO_UNION,
+  SGEIOUnion_t, MPI_POINTER pSGEIOUnion_t;
+
+/****************************************************************************/
+/*  SGE union for SGL's with Simple and Transaction elements                */
+/****************************************************************************/
+
+typedef struct _SGE_TRANS_SIMPLE_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION        Simple;
+        SGE_TRANSACTION_UNION   Transaction;
+    } u;
+} SGE_TRANS_SIMPLE_UNION, MPI_POINTER PTR_SGE_TRANS_SIMPLE_UNION,
+  SGETransSimpleUnion_t, MPI_POINTER pSGETransSimpleUnion_t;
+
+/****************************************************************************/
+/*  All SGE types union                                                     */
+/****************************************************************************/
+
+typedef struct _SGE_MPI_UNION
+{
+    union
+    {
+        SGE_SIMPLE_UNION        Simple;
+        SGE_CHAIN_UNION         Chain;
+        SGE_TRANSACTION_UNION   Transaction;
+    } u;
+} SGE_MPI_UNION, MPI_POINTER PTR_SGE_MPI_UNION,
+  MPI_SGE_UNION_t, MPI_POINTER pMPI_SGE_UNION_t,
+  SGEAllUnion_t, MPI_POINTER pSGEAllUnion_t;
+
+
+/****************************************************************************/
+/*  SGE field definition and masks                                          */
+/****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI_SGE_FLAGS_LAST_ELEMENT              (0x80)
+#define MPI_SGE_FLAGS_END_OF_BUFFER             (0x40)
+#define MPI_SGE_FLAGS_ELEMENT_TYPE_MASK         (0x30)
+#define MPI_SGE_FLAGS_LOCAL_ADDRESS             (0x08)
+#define MPI_SGE_FLAGS_DIRECTION                 (0x04)
+#define MPI_SGE_FLAGS_ADDRESS_SIZE              (0x02)
+#define MPI_SGE_FLAGS_END_OF_LIST               (0x01)
+
+#define MPI_SGE_FLAGS_SHIFT                     (24)
+
+#define MPI_SGE_LENGTH_MASK                     (0x00FFFFFF)
+#define MPI_SGE_CHAIN_LENGTH_MASK               (0x0000FFFF)
+
+/* Element Type */
+
+#define MPI_SGE_FLAGS_TRANSACTION_ELEMENT       (0x00)
+#define MPI_SGE_FLAGS_SIMPLE_ELEMENT            (0x10)
+#define MPI_SGE_FLAGS_CHAIN_ELEMENT             (0x30)
+#define MPI_SGE_FLAGS_ELEMENT_MASK              (0x30)
+
+/* Address location */
+
+#define MPI_SGE_FLAGS_SYSTEM_ADDRESS            (0x00)
+
+/* Direction */
+
+#define MPI_SGE_FLAGS_IOC_TO_HOST               (0x00)
+#define MPI_SGE_FLAGS_HOST_TO_IOC               (0x04)
+
+/* Address Size */
+
+#define MPI_SGE_FLAGS_32_BIT_ADDRESSING         (0x00)
+#define MPI_SGE_FLAGS_64_BIT_ADDRESSING         (0x02)
+
+/* Context Size */
+
+#define MPI_SGE_FLAGS_32_BIT_CONTEXT            (0x00)
+#define MPI_SGE_FLAGS_64_BIT_CONTEXT            (0x02)
+#define MPI_SGE_FLAGS_96_BIT_CONTEXT            (0x04)
+#define MPI_SGE_FLAGS_128_BIT_CONTEXT           (0x06)
+
+#define MPI_SGE_CHAIN_OFFSET_MASK               (0x00FF0000)
+#define MPI_SGE_CHAIN_OFFSET_SHIFT              (16)
+
+
+/****************************************************************************/
+/*  SGE operation Macros                                                    */
+/****************************************************************************/
+
+         /* SIMPLE FlagsLength manipulations... */
+#define  MPI_SGE_SET_FLAGS(f)           ((U32)(f) << MPI_SGE_FLAGS_SHIFT)
+#define  MPI_SGE_GET_FLAGS(fl)          (((fl) & ~MPI_SGE_LENGTH_MASK) >> MPI_SGE_FLAGS_SHIFT)
+#define  MPI_SGE_LENGTH(fl)             ((fl) & MPI_SGE_LENGTH_MASK)
+#define  MPI_SGE_CHAIN_LENGTH(fl)       ((fl) & MPI_SGE_CHAIN_LENGTH_MASK)
+
+#define  MPI_SGE_SET_FLAGS_LENGTH(f,l)  (MPI_SGE_SET_FLAGS(f) | MPI_SGE_LENGTH(l))
+
+#define  MPI_pSGE_GET_FLAGS(psg)        MPI_SGE_GET_FLAGS((psg)->FlagsLength)
+#define  MPI_pSGE_GET_LENGTH(psg)       MPI_SGE_LENGTH((psg)->FlagsLength)
+#define  MPI_pSGE_SET_FLAGS_LENGTH(psg,f,l)  (psg)->FlagsLength = MPI_SGE_SET_FLAGS_LENGTH(f,l)
+         /* CAUTION - The following are READ-MODIFY-WRITE! */
+#define  MPI_pSGE_SET_FLAGS(psg,f)      (psg)->FlagsLength |= MPI_SGE_SET_FLAGS(f)
+#define  MPI_pSGE_SET_LENGTH(psg,l)     (psg)->FlagsLength |= MPI_SGE_LENGTH(l)
+
+#define  MPI_GET_CHAIN_OFFSET(x) ((x&MPI_SGE_CHAIN_OFFSET_MASK)>>MPI_SGE_CHAIN_OFFSET_SHIFT)
+
+
+
+/*****************************************************************************
+*
+*        S t a n d a r d    M e s s a g e    S t r u c t u r e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Standard message request header for all request messages                 */
+/****************************************************************************/
+
+typedef struct _MSG_REQUEST_HEADER
+{
+    U8                      Reserved[2];      /* function specific */
+    U8                      ChainOffset;
+    U8                      Function;
+    U8                      Reserved1[3];     /* function specific */
+    U8                      MsgFlags;
+    U32                     MsgContext;
+} MSG_REQUEST_HEADER, MPI_POINTER PTR_MSG_REQUEST_HEADER,
+  MPIHeader_t, MPI_POINTER pMPIHeader_t;
+
+
+/****************************************************************************/
+/*  Default Reply                                                           */
+/****************************************************************************/
+
+typedef struct _MSG_DEFAULT_REPLY
+{
+    U8                      Reserved[2];      /* function specific */
+    U8                      MsgLength;
+    U8                      Function;
+    U8                      Reserved1[3];     /* function specific */
+    U8                      MsgFlags;
+    U32                     MsgContext;
+    U8                      Reserved2[2];     /* function specific */
+    U16                     IOCStatus;
+    U32                     IOCLogInfo;
+} MSG_DEFAULT_REPLY, MPI_POINTER PTR_MSG_DEFAULT_REPLY,
+  MPIDefaultReply_t, MPI_POINTER pMPIDefaultReply_t;
+
+
+/* MsgFlags definition for all replies */
+
+#define MPI_MSGFLAGS_CONTINUATION_REPLY         (0x80)
+
+
+/*****************************************************************************
+*
+*               I O C    S t a t u s   V a l u e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Common IOCStatus values for all replies                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SUCCESS                  (0x0000)
+#define MPI_IOCSTATUS_INVALID_FUNCTION         (0x0001)
+#define MPI_IOCSTATUS_BUSY                     (0x0002)
+#define MPI_IOCSTATUS_INVALID_SGL              (0x0003)
+#define MPI_IOCSTATUS_INTERNAL_ERROR           (0x0004)
+#define MPI_IOCSTATUS_RESERVED                 (0x0005)
+#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES   (0x0006)
+#define MPI_IOCSTATUS_INVALID_FIELD            (0x0007)
+#define MPI_IOCSTATUS_INVALID_STATE            (0x0008)
+
+/****************************************************************************/
+/*  Config IOCStatus values                                                 */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION    (0x0020)
+#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE      (0x0021)
+#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE      (0x0022)
+#define MPI_IOCSTATUS_CONFIG_INVALID_DATA      (0x0023)
+#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS       (0x0024)
+#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT       (0x0025)
+
+/****************************************************************************/
+/*  SCSIIO Reply (SPI & FCP) initiator values                               */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR     (0x0040)
+#define MPI_IOCSTATUS_SCSI_INVALID_BUS         (0x0041)
+#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID    (0x0042)
+#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE    (0x0043)
+#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN        (0x0044)
+#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN       (0x0045)
+#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR       (0x0046)
+#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR      (0x0047)
+#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED     (0x0048)
+#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH   (0x0049)
+#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED    (0x004A)
+#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED      (0x004B)
+#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED      (0x004C)
+
+/****************************************************************************/
+/*  SCSI (SPI & FCP) target values                                          */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_PRIORITY_IO         (0x0060)
+#define MPI_IOCSTATUS_TARGET_INVALID_PORT        (0x0061)
+#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX    (0x0062)
+#define MPI_IOCSTATUS_TARGET_ABORTED             (0x0063)
+#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE   (0x0064)
+#define MPI_IOCSTATUS_TARGET_NO_CONNECTION       (0x0065)
+#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
+#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT   (0x006B)
+
+/****************************************************************************/
+/*  Additional FCP target values                                            */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_TARGET_FC_ABORTED         (0x0066)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID   (0x0067)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID     (0x0068)    /* obsolete */
+#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069)    /* obsolete */
+
+/****************************************************************************/
+/*  Fibre Channel Direct Access values                                      */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FC_ABORTED                (0x0066)
+#define MPI_IOCSTATUS_FC_RX_ID_INVALID          (0x0067)
+#define MPI_IOCSTATUS_FC_DID_INVALID            (0x0068)
+#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT        (0x0069)
+
+/****************************************************************************/
+/*  LAN values                                                              */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND      (0x0080)
+#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE        (0x0081)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR        (0x0082)
+#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED      (0x0083)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR         (0x0084)
+#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED       (0x0085)
+#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET        (0x0086)
+#define MPI_IOCSTATUS_LAN_CANCELED              (0x0087)
+
+
+/****************************************************************************/
+/*  IOCStatus flag to indicate that log info is available                   */
+/****************************************************************************/
+
+#define MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE   (0x8000)
+#define MPI_IOCSTATUS_MASK                      (0x7FFF)
+
+/****************************************************************************/
+/*  LogInfo Types                                                           */
+/****************************************************************************/
+
+#define MPI_IOCLOGINFO_TYPE_MASK                (0xF0000000)
+#define MPI_IOCLOGINFO_TYPE_NONE                (0x0)
+#define MPI_IOCLOGINFO_TYPE_SCSI                (0x1)
+#define MPI_IOCLOGINFO_TYPE_FC                  (0x2)
+#define MPI_IOCLOGINFO_LOG_DATA_MASK            (0x0FFFFFFF)
+
+
+#endif
diff --git a/xen/drivers/message/fusion/lsi/mpi_cnfg.h b/xen/drivers/message/fusion/lsi/mpi_cnfg.h
new file mode 100644 (file)
index 0000000..47a5afc
--- /dev/null
@@ -0,0 +1,1569 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_CNFG.H
+ *          Title:  MPI Config message, structures, and Pages
+ *  Creation Date:  July 27, 2000
+ *
+ *    MPI_CNFG.H Version:  01.02.09
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added _PAGEVERSION definitions for all pages.
+ *                      Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ *                      fields to FC_DEVICE_0 page, updated the page version.
+ *                      Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ *                      SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ *                      and updated the page versions.
+ *                      Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ *                      page and updated the page version.
+ *                      Added Information field and _INFO_PARAMS_NEGOTIATED
+ *                      definitionto SCSI_DEVICE_0 page.
+ *  06-22-00  01.00.03  Removed batch controls from LAN_0 page and updated the
+ *                      page version.
+ *                      Added BucketsRemaining to LAN_1 page, redefined the
+ *                      state values, and updated the page version.
+ *                      Revised bus width definitions in SCSI_PORT_0,
+ *                      SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ *  06-30-00  01.00.04  Added MaxReplySize to LAN_1 page and updated the page
+ *                      version.
+ *                      Moved FC_DEVICE_0 PageAddress description to spec.
+ *  07-27-00  01.00.05  Corrected the SubsystemVendorID and SubsystemID field
+ *                      widths in IOC_0 page and updated the page version.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ *                      Port Page 2, FC Port Page 4, FC Port Page 5
+ *  11-15-00  01.01.02  Interim changes to match proposals
+ *  12-04-00  01.01.03  Config page changes to match MPI rev 1.00.01.
+ *  12-05-00  01.01.04  Modified config page actions.
+ *  01-09-01  01.01.05  Added defines for page address formats.
+ *                      Data size for Manufacturing pages 2 and 3 no longer
+ *                      defined here.
+ *                      Io Unit Page 2 size is fixed at 4 adapters and some
+ *                      flags were changed.
+ *                      SCSI Port Page 2 Device Settings modified.
+ *                      New fields added to FC Port Page 0 and some flags
+ *                      cleaned up.
+ *                      Removed impedance flash from FC Port Page 1.
+ *                      Added FC Port pages 6 and 7.
+ *  01-25-01  01.01.06  Added MaxInitiators field to FcPortPage0.
+ *  01-29-01  01.01.07  Changed some defines to make them 32 character unique.
+ *                      Added some LinkType defines for FcPortPage0.
+ *  02-20-01  01.01.08  Started using MPI_POINTER.
+ *  02-27-01  01.01.09  Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ *                      MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ *                      Added definitions and structures for IOC Page 2 and
+ *                      RAID Volume Page 2.
+ *  03-27-01  01.01.10  Added CONFIG_PAGE_FC_PORT_8 and CONFIG_PAGE_FC_PORT_9.
+ *                      CONFIG_PAGE_FC_PORT_3 now supports persistent by DID.
+ *                      Added VendorId and ProductRevLevel fields to
+ *                      RAIDVOL2_IM_PHYS_ID struct.
+ *                      Modified values for MPI_FCPORTPAGE0_FLAGS_ATTACH_
+ *                      defines to make them compatible to MPI version 1.0.
+ *                      Added structure offset comments.
+ *  04-09-01  01.01.11  Added some new defines for the PageAddress field and
+ *                      removed some obsolete ones.
+ *                      Added IO Unit Page 3.
+ *                      Modified defines for Scsi Port Page 2.
+ *                      Modified RAID Volume Pages.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      Added SepID and SepBus to RVP2 IMPhysicalDisk struct.
+ *                      Added defines for the SEP bits in RVP2 VolumeSettings.
+ *                      Modified the DeviceSettings field in RVP2 to use the
+ *                      proper structure.
+ *                      Added defines for SES, SAF-TE, and cross channel for
+ *                      IOCPage2 CapabilitiesFlags.
+ *                      Removed define for MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE.
+ *                      Removed define for
+ *                      MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE.
+ *                      Added define for MPI_CONFIG_PAGEATTR_RO_PERSISTENT.
+ *  08-29-01 01.02.02   Fixed value for MPI_MANUFACTPAGE_DEVID_53C1035.
+ *                      Added defines for MPI_FCPORTPAGE1_FLAGS_HARD_ALPA_ONLY
+ *                      and MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY.
+ *                      Removed MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS,
+ *                      MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS, and
+ *                      MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED.
+ *                      Added defines for MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED
+ *                      and MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED.
+ *                      Added OnBusTimerValue to CONFIG_PAGE_SCSI_PORT_1.
+ *                      Added rejected bits to SCSI Device Page 0 Information.
+ *                      Increased size of ALPA array in FC Port Page 2 by one
+ *                      and removed a one byte reserved field.
+ *  09-28-01 01.02.03   Swapped NegWireSpeedLow and NegWireSpeedLow in
+ *                      CONFIG_PAGE_LAN_1 to match preferred 64-bit ordering.
+ *                      Added structures for Manufacturing Page 4, IO Unit
+ *                      Page 3, IOC Page 3, IOC Page 4, RAID Volume Page 0, and
+ *                      RAID PhysDisk Page 0.
+ *  10-04-01 01.02.04   Added define for MPI_CONFIG_PAGETYPE_RAID_PHYSDISK.
+ *                      Modified some of the new defines to make them 32
+ *                      character unique.
+ *                      Modified how variable length pages (arrays) are defined.
+ *                      Added generic defines for hot spare pools and RAID
+ *                      volume types.
+ *  11-01-01 01.02.05   Added define for MPI_IOUNITPAGE1_DISABLE_IR.
+ *  03-14-02 01.02.06   Added PCISlotNum field to CONFIG_PAGE_IOC_1 along with
+ *                      related define, and bumped the page version define.
+ *  05-31-02 01.02.07   Added a Flags field to CONFIG_PAGE_IOC_2_RAID_VOL in a
+ *                      reserved byte and added a define.
+ *                      Added define for
+ *                      MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE.
+ *                      Added new config page: CONFIG_PAGE_IOC_5.
+ *                      Added MaxAliases, MaxHardAliases, and NumCurrentAliases
+ *                      fields to CONFIG_PAGE_FC_PORT_0.
+ *                      Added AltConnector and NumRequestedAliases fields to
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added new config page: CONFIG_PAGE_FC_PORT_10.
+ *  07-12-02 01.02.08   Added more MPI_MANUFACTPAGE_DEVID_ defines.
+ *                      Added additional MPI_SCSIDEVPAGE0_NP_ defines.
+ *                      Added more MPI_SCSIDEVPAGE1_RP_ defines.
+ *                      Added define for
+ *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
+ *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
+ *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
+ *  09-16-02 01.02.09   Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_CNFG_H
+#define MPI_CNFG_H
+
+
+/*****************************************************************************
+*
+*       C o n f i g    M e s s a g e    a n d    S t r u c t u r e s
+*
+*****************************************************************************/
+
+typedef struct _CONFIG_PAGE_HEADER
+{
+    U8                      PageVersion;                /* 00h */
+    U8                      PageLength;                 /* 01h */
+    U8                      PageNumber;                 /* 02h */
+    U8                      PageType;                   /* 03h */
+} fCONFIG_PAGE_HEADER, MPI_POINTER PTR_CONFIG_PAGE_HEADER,
+  ConfigPageHeader_t, MPI_POINTER pConfigPageHeader_t;
+
+typedef union _CONFIG_PAGE_HEADER_UNION
+{
+   ConfigPageHeader_t  Struct;
+   U8                  Bytes[4];
+   U16                 Word16[2];
+   U32                 Word32;
+} ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion,
+  fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION;
+
+
+/****************************************************************************
+*   PageType field values
+****************************************************************************/
+#define MPI_CONFIG_PAGEATTR_READ_ONLY               (0x00)
+#define MPI_CONFIG_PAGEATTR_CHANGEABLE              (0x10)
+#define MPI_CONFIG_PAGEATTR_PERSISTENT              (0x20)
+#define MPI_CONFIG_PAGEATTR_RO_PERSISTENT           (0x30)
+#define MPI_CONFIG_PAGEATTR_MASK                    (0xF0)
+
+#define MPI_CONFIG_PAGETYPE_IO_UNIT                 (0x00)
+#define MPI_CONFIG_PAGETYPE_IOC                     (0x01)
+#define MPI_CONFIG_PAGETYPE_BIOS                    (0x02)
+#define MPI_CONFIG_PAGETYPE_SCSI_PORT               (0x03)
+#define MPI_CONFIG_PAGETYPE_SCSI_DEVICE             (0x04)
+#define MPI_CONFIG_PAGETYPE_FC_PORT                 (0x05)
+#define MPI_CONFIG_PAGETYPE_FC_DEVICE               (0x06)
+#define MPI_CONFIG_PAGETYPE_LAN                     (0x07)
+#define MPI_CONFIG_PAGETYPE_RAID_VOLUME             (0x08)
+#define MPI_CONFIG_PAGETYPE_MANUFACTURING           (0x09)
+#define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK           (0x0A)
+#define MPI_CONFIG_PAGETYPE_MASK                    (0x0F)
+
+#define MPI_CONFIG_TYPENUM_MASK                     (0x0FFF)
+
+
+/****************************************************************************
+*   PageAddress field values
+****************************************************************************/
+#define MPI_SCSI_PORT_PGAD_PORT_MASK                (0x000000FF)
+
+#define MPI_SCSI_DEVICE_TARGET_ID_MASK              (0x000000FF)
+#define MPI_SCSI_DEVICE_TARGET_ID_SHIFT             (0)
+#define MPI_SCSI_DEVICE_BUS_MASK                    (0x0000FF00)
+#define MPI_SCSI_DEVICE_BUS_SHIFT                   (8)
+
+#define MPI_FC_PORT_PGAD_PORT_MASK                  (0xF0000000)
+#define MPI_FC_PORT_PGAD_PORT_SHIFT                 (28)
+#define MPI_FC_PORT_PGAD_FORM_MASK                  (0x0F000000)
+#define MPI_FC_PORT_PGAD_FORM_INDEX                 (0x01000000)
+#define MPI_FC_PORT_PGAD_INDEX_MASK                 (0x0000FFFF)
+#define MPI_FC_PORT_PGAD_INDEX_SHIFT                (0)
+
+#define MPI_FC_DEVICE_PGAD_PORT_MASK                (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_PORT_SHIFT               (28)
+#define MPI_FC_DEVICE_PGAD_FORM_MASK                (0x0F000000)
+#define MPI_FC_DEVICE_PGAD_FORM_NEXT_DID            (0x00000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_MASK             (0xF0000000)
+#define MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT            (28)
+#define MPI_FC_DEVICE_PGAD_ND_DID_MASK              (0x00FFFFFF)
+#define MPI_FC_DEVICE_PGAD_ND_DID_SHIFT             (0)
+#define MPI_FC_DEVICE_PGAD_FORM_BUS_TID             (0x01000000)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_MASK              (0x0000FF00)
+#define MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT             (8)
+#define MPI_FC_DEVICE_PGAD_BT_TID_MASK              (0x000000FF)
+#define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT             (0)
+
+#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK          (0x000000FF)
+#define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT         (0)
+
+
+
+/****************************************************************************
+*   Config Request Message
+****************************************************************************/
+typedef struct _MSG_CONFIG
+{
+    U8                      Action;                     /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      Reserved2[8];               /* 0Ch */
+    fCONFIG_PAGE_HEADER      Header;                     /* 14h */
+    U32                     PageAddress;                /* 18h */
+    SGE_IO_UNION            PageBufferSGE;              /* 1Ch */
+} MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG,
+  Config_t, MPI_POINTER pConfig_t;
+
+
+/****************************************************************************
+*   Action field values
+****************************************************************************/
+#define MPI_CONFIG_ACTION_PAGE_HEADER               (0x00)
+#define MPI_CONFIG_ACTION_PAGE_READ_CURRENT         (0x01)
+#define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT        (0x02)
+#define MPI_CONFIG_ACTION_PAGE_DEFAULT              (0x03)
+#define MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM          (0x04)
+#define MPI_CONFIG_ACTION_PAGE_READ_DEFAULT         (0x05)
+#define MPI_CONFIG_ACTION_PAGE_READ_NVRAM           (0x06)
+
+
+/* Config Reply Message */
+typedef struct _MSG_CONFIG_REPLY
+{
+    U8                      Action;                     /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      Reserved2[2];               /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    fCONFIG_PAGE_HEADER      Header;                     /* 14h */
+} MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY,
+  ConfigReply_t, MPI_POINTER pConfigReply_t;
+
+
+
+/*****************************************************************************
+*
+*               C o n f i g u r a t i o n    P a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************
+*   Manufacturing Config pages
+****************************************************************************/
+#define MPI_MANUFACTPAGE_DEVICEID_FC909             (0x0621)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919             (0x0624)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
+#define MPI_MANUFACTPAGE_DEVICEID_FC919X            (0x0628)
+#define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
+
+#define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
+#define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
+#define MPI_MANUFACTPAGE_DEVID_1030_53C1035         (0x0032)
+#define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035       (0x0033)
+#define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0040)
+#define MPI_MANUFACTPAGE_DEVID_53C1035ZC            (0x0041)
+
+#define MPI_MANUFACTPAGE_DEVID_SA2010               (0x0804)
+#define MPI_MANUFACTPAGE_DEVID_SA2010ZC             (0x0805)
+#define MPI_MANUFACTPAGE_DEVID_SA2020               (0x0806)
+#define MPI_MANUFACTPAGE_DEVID_SA2020ZC             (0x0807)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U8                      ChipName[16];               /* 04h */
+    U8                      ChipRevision[8];            /* 14h */
+    U8                      BoardName[16];              /* 1Ch */
+    U8                      BoardAssembly[16];          /* 2Ch */
+    U8                      BoardTracerNumber[16];      /* 3Ch */
+
+} fCONFIG_PAGE_MANUFACTURING_0, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_0,
+  ManufacturingPage0_t, MPI_POINTER pManufacturingPage0_t;
+
+#define MPI_MANUFACTURING0_PAGEVERSION                 (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U8                      VPD[256];                   /* 04h */
+} fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1,
+  ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t;
+
+#define MPI_MANUFACTURING1_PAGEVERSION                 (0x00)
+
+
+typedef struct _MPI_CHIP_REVISION_ID
+{
+    U16 DeviceID;                                       /* 00h */
+    U8  PCIRevisionID;                                  /* 02h */
+    U8  Reserved;                                       /* 03h */
+} MPI_CHIP_REVISION_ID, MPI_POINTER PTR_MPI_CHIP_REVISION_ID,
+  MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t;
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_MAN_PAGE_2_HW_SETTINGS_WORDS
+#define MPI_MAN_PAGE_2_HW_SETTINGS_WORDS    (1)
+#endif
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_2
+{
+    fCONFIG_PAGE_HEADER      Header;                                 /* 00h */
+    MPI_CHIP_REVISION_ID    ChipId;                                 /* 04h */
+    U32                     HwSettings[MPI_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 08h */
+} fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2,
+  ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t;
+
+#define MPI_MANUFACTURING2_PAGEVERSION                  (0x00)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_MAN_PAGE_3_INFO_WORDS
+#define MPI_MAN_PAGE_3_INFO_WORDS           (1)
+#endif
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_3
+{
+    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
+    MPI_CHIP_REVISION_ID                ChipId;                     /* 04h */
+    U32                                 Info[MPI_MAN_PAGE_3_INFO_WORDS];/* 08h */
+} fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3,
+  ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t;
+
+#define MPI_MANUFACTURING3_PAGEVERSION                  (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_4
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U32                             Reserved1;          /* 04h */
+    U8                              InfoOffset0;        /* 08h */
+    U8                              InfoSize0;          /* 09h */
+    U8                              InfoOffset1;        /* 0Ah */
+    U8                              InfoSize1;          /* 0Bh */
+    U8                              InquirySize;        /* 0Ch */
+    U8                              Reserved2;          /* 0Dh */
+    U16                             Reserved3;          /* 0Eh */
+    U8                              InquiryData[56];    /* 10h */
+    U32                             ISVolumeSettings;   /* 48h */
+    U32                             IMEVolumeSettings;  /* 4Ch */
+    U32                             IMVolumeSettings;   /* 50h */
+} fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
+  ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
+
+#define MPI_MANUFACTURING4_PAGEVERSION                  (0x00)
+
+
+/****************************************************************************
+*   IO Unit Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IO_UNIT_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U64                     UniqueValue;                /* 04h */
+} fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0,
+  IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t;
+
+#define MPI_IOUNITPAGE0_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_IO_UNIT_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Flags;                      /* 04h */
+} fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
+  IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
+
+#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x00)
+
+/* IO Unit Page 1 Flags defines */
+
+#define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
+#define MPI_IOUNITPAGE1_SINGLE_FUNCTION                 (0x00000001)
+#define MPI_IOUNITPAGE1_MULTI_PATHING                   (0x00000002)
+#define MPI_IOUNITPAGE1_SINGLE_PATHING                  (0x00000000)
+#define MPI_IOUNITPAGE1_DISABLE_IR                      (0x00000040)
+#define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
+
+
+typedef struct _MPI_ADAPTER_INFO
+{
+    U8      PciBusNumber;                               /* 00h */
+    U8      PciDeviceAndFunctionNumber;                 /* 01h */
+    U16     AdapterFlags;                               /* 02h */
+} MPI_ADAPTER_INFO, MPI_POINTER PTR_MPI_ADAPTER_INFO,
+  MpiAdapterInfo_t, MPI_POINTER pMpiAdapterInfo_t;
+
+#define MPI_ADAPTER_INFO_FLAGS_EMBEDDED                 (0x0001)
+#define MPI_ADAPTER_INFO_FLAGS_INIT_STATUS              (0x0002)
+
+typedef struct _CONFIG_PAGE_IO_UNIT_2
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Flags;                      /* 04h */
+    U32                     BiosVersion;                /* 08h */
+    MPI_ADAPTER_INFO        AdapterOrder[4];            /* 0Ch */
+} fCONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2,
+  IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t;
+
+#define MPI_IOUNITPAGE2_PAGEVERSION                     (0x00)
+
+#define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR            (0x00000002)
+#define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE            (0x00000004)
+#define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE       (0x00000008)
+#define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40          (0x00000010)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX
+#define MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX     (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IO_UNIT_3
+{
+    fCONFIG_PAGE_HEADER      Header;                                   /* 00h */
+    U8                      GPIOCount;                                /* 04h */
+    U8                      Reserved1;                                /* 05h */
+    U16                     Reserved2;                                /* 06h */
+    U16                     GPIOVal[MPI_IO_UNIT_PAGE_3_GPIO_VAL_MAX]; /* 08h */
+} fCONFIG_PAGE_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_3,
+  IOUnitPage3_t, MPI_POINTER pIOUnitPage3_t;
+
+#define MPI_IOUNITPAGE3_PAGEVERSION                     (0x01)
+
+#define MPI_IOUNITPAGE3_GPIO_FUNCTION_MASK              (0xFC)
+#define MPI_IOUNITPAGE3_GPIO_FUNCTION_SHIFT             (2)
+#define MPI_IOUNITPAGE3_GPIO_SETTING_OFF                (0x00)
+#define MPI_IOUNITPAGE3_GPIO_SETTING_ON                 (0x01)
+
+
+/****************************************************************************
+*   IOC Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_IOC_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     TotalNVStore;               /* 04h */
+    U32                     FreeNVStore;                /* 08h */
+    U16                     VendorID;                   /* 0Ch */
+    U16                     DeviceID;                   /* 0Eh */
+    U8                      RevisionID;                 /* 10h */
+    U8                      Reserved[3];                /* 11h */
+    U32                     ClassCode;                  /* 14h */
+    U16                     SubsystemVendorID;          /* 18h */
+    U16                     SubsystemID;                /* 1Ah */
+} fCONFIG_PAGE_IOC_0, MPI_POINTER PTR_CONFIG_PAGE_IOC_0,
+  IOCPage0_t, MPI_POINTER pIOCPage0_t;
+
+#define MPI_IOCPAGE0_PAGEVERSION                        (0x01)
+
+
+typedef struct _CONFIG_PAGE_IOC_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Flags;                      /* 04h */
+    U32                     CoalescingTimeout;          /* 08h */
+    U8                      CoalescingDepth;            /* 0Ch */
+    U8                      PCISlotNum;                 /* 0Dh */
+    U8                      Reserved[2];                /* 0Eh */
+} fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1,
+  IOCPage1_t, MPI_POINTER pIOCPage1_t;
+
+#define MPI_IOCPAGE1_PAGEVERSION                        (0x01)
+
+#define MPI_IOCPAGE1_REPLY_COALESCING                   (0x00000001)
+
+#define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN                 (0xFF)
+
+
+typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
+{
+    U8                          VolumeID;               /* 00h */
+    U8                          VolumeBus;              /* 01h */
+    U8                          VolumeIOC;              /* 02h */
+    U8                          VolumePageNumber;       /* 03h */
+    U8                          VolumeType;             /* 04h */
+    U8                          Flags;                  /* 05h */
+    U16                         Reserved3;              /* 06h */
+} fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
+  ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
+
+/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
+
+#define MPI_RAID_VOL_TYPE_IS                        (0x00)
+#define MPI_RAID_VOL_TYPE_IME                       (0x01)
+#define MPI_RAID_VOL_TYPE_IM                        (0x02)
+
+/* IOC Page 2 Volume Flags values */
+
+#define MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE           (0x08)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_2_RAID_VOLUME_MAX
+#define MPI_IOC_PAGE_2_RAID_VOLUME_MAX      (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_2
+{
+    fCONFIG_PAGE_HEADER          Header;                              /* 00h */
+    U32                         CapabilitiesFlags;                   /* 04h */
+    U8                          NumActiveVolumes;                    /* 08h */
+    U8                          MaxVolumes;                          /* 09h */
+    U8                          NumActivePhysDisks;                  /* 0Ah */
+    U8                          MaxPhysDisks;                        /* 0Bh */
+    fCONFIG_PAGE_IOC_2_RAID_VOL  RaidVolume[MPI_IOC_PAGE_2_RAID_VOLUME_MAX];/* 0Ch */
+} fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
+  IOCPage2_t, MPI_POINTER pIOCPage2_t;
+
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x02)
+
+/* IOC Page 2 Capabilities flags */
+
+#define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT               (0x00000001)
+#define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT              (0x00000002)
+#define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT               (0x00000004)
+#define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT              (0x20000000)
+#define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT            (0x40000000)
+#define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT    (0x80000000)
+
+
+typedef struct _IOC_3_PHYS_DISK
+{
+    U8                          PhysDiskID;             /* 00h */
+    U8                          PhysDiskBus;            /* 01h */
+    U8                          PhysDiskIOC;            /* 02h */
+    U8                          PhysDiskNum;            /* 03h */
+} IOC_3_PHYS_DISK, MPI_POINTER PTR_IOC_3_PHYS_DISK,
+  Ioc3PhysDisk_t, MPI_POINTER pIoc3PhysDisk_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_3_PHYSDISK_MAX
+#define MPI_IOC_PAGE_3_PHYSDISK_MAX         (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_3
+{
+    fCONFIG_PAGE_HEADER          Header;                                /* 00h */
+    U8                          NumPhysDisks;                          /* 04h */
+    U8                          Reserved1;                             /* 05h */
+    U16                         Reserved2;                             /* 06h */
+    IOC_3_PHYS_DISK             PhysDisk[MPI_IOC_PAGE_3_PHYSDISK_MAX]; /* 08h */
+} fCONFIG_PAGE_IOC_3, MPI_POINTER PTR_CONFIG_PAGE_IOC_3,
+  IOCPage3_t, MPI_POINTER pIOCPage3_t;
+
+#define MPI_IOCPAGE3_PAGEVERSION                        (0x00)
+
+
+typedef struct _IOC_4_SEP
+{
+    U8                          SEPTargetID;            /* 00h */
+    U8                          SEPBus;                 /* 01h */
+    U16                         Reserved;               /* 02h */
+} IOC_4_SEP, MPI_POINTER PTR_IOC_4_SEP,
+  Ioc4Sep_t, MPI_POINTER pIoc4Sep_t;
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_4_SEP_MAX
+#define MPI_IOC_PAGE_4_SEP_MAX              (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_4
+{
+    fCONFIG_PAGE_HEADER          Header;                         /* 00h */
+    U8                          ActiveSEP;                      /* 04h */
+    U8                          MaxSEP;                         /* 05h */
+    U16                         Reserved1;                      /* 06h */
+    IOC_4_SEP                   SEP[MPI_IOC_PAGE_4_SEP_MAX];    /* 08h */
+} fCONFIG_PAGE_IOC_4, MPI_POINTER PTR_CONFIG_PAGE_IOC_4,
+  IOCPage4_t, MPI_POINTER pIOCPage4_t;
+
+#define MPI_IOCPAGE4_PAGEVERSION                        (0x00)
+
+
+typedef struct _IOC_5_HOT_SPARE
+{
+    U8                          PhysDiskNum;            /* 00h */
+    U8                          Reserved;               /* 01h */
+    U8                          HotSparePool;           /* 02h */
+    U8                          Flags;                   /* 03h */
+} IOC_5_HOT_SPARE, MPI_POINTER PTR_IOC_5_HOT_SPARE,
+  Ioc5HotSpare_t, MPI_POINTER pIoc5HotSpare_t;
+
+/* IOC Page 5 HotSpare Flags */
+#define MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE                 (0x01)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_5_HOT_SPARE_MAX
+#define MPI_IOC_PAGE_5_HOT_SPARE_MAX        (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_5
+{
+    fCONFIG_PAGE_HEADER         Header;                         /* 00h */
+    U32                         Reserved1;                      /* 04h */
+    U8                          NumHotSpares;                   /* 08h */
+    U8                          Reserved2;                      /* 09h */
+    U16                         Reserved3;                      /* 0Ah */
+    IOC_5_HOT_SPARE             HotSpare[MPI_IOC_PAGE_5_HOT_SPARE_MAX]; /* 0Ch */
+} fCONFIG_PAGE_IOC_5, MPI_POINTER PTR_CONFIG_PAGE_IOC_5,
+  IOCPage5_t, MPI_POINTER pIOCPage5_t;
+
+#define MPI_IOCPAGE5_PAGEVERSION                        (0x00)
+
+
+
+/****************************************************************************
+*   SCSI Port Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Capabilities;               /* 04h */
+    U32                     PhysicalInterface;          /* 08h */
+} fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0,
+  SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t;
+
+#define MPI_SCSIPORTPAGE0_PAGEVERSION                   (0x01)
+
+#define MPI_SCSIPORTPAGE0_CAP_IU                        (0x00000001)
+#define MPI_SCSIPORTPAGE0_CAP_DT                        (0x00000002)
+#define MPI_SCSIPORTPAGE0_CAP_QAS                       (0x00000004)
+#define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK      (0x0000FF00)
+#define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
+#define MPI_SCSIPORTPAGE0_CAP_WIDE                      (0x20000000)
+#define MPI_SCSIPORTPAGE0_CAP_AIP                       (0x80000000)
+
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK          (0x00000003)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD                (0x01)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE                 (0x02)
+#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD                (0x03)
+
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Configuration;              /* 04h */
+    U32                     OnBusTimerValue;            /* 08h */
+} fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1,
+  SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t;
+
+#define MPI_SCSIPORTPAGE1_PAGEVERSION                   (0x02)
+
+#define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK         (0x000000FF)
+#define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK     (0xFFFF0000)
+
+
+typedef struct _MPI_DEVICE_INFO
+{
+    U8      Timeout;                                    /* 00h */
+    U8      SyncFactor;                                 /* 01h */
+    U16     DeviceFlags;                                /* 02h */
+} MPI_DEVICE_INFO, MPI_POINTER PTR_MPI_DEVICE_INFO,
+  MpiDeviceInfo_t, MPI_POINTER pMpiDeviceInfo_t;
+
+typedef struct _CONFIG_PAGE_SCSI_PORT_2
+{
+    fCONFIG_PAGE_HEADER  Header;                         /* 00h */
+    U32                 PortFlags;                      /* 04h */
+    U32                 PortSettings;                   /* 08h */
+    MPI_DEVICE_INFO     DeviceSettings[16];             /* 0Ch */
+} fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2,
+  SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t;
+
+#define MPI_SCSIPORTPAGE2_PAGEVERSION                       (0x01)
+
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW       (0x00000001)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET       (0x00000004)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS          (0x00000008)
+#define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE    (0x00000010)
+
+#define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK                 (0x0000000F)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA                (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA             (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_INIT_HBA                (0x00000010)
+#define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA                  (0x00000020)
+#define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA             (0x00000030)
+#define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA              (0x000000C0)
+#define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK            (0x00000F00)
+#define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS    (0x00003000)
+#define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS         (0x00000000)
+#define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS         (0x00001000)
+#define MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS          (0x00003000)
+
+#define MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE          (0x0001)
+#define MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE             (0x0002)
+#define MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE            (0x0004)
+#define MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE           (0x0008)
+#define MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE               (0x0010)
+#define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE                (0x0020)
+
+
+/****************************************************************************
+*   SCSI Target Device Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     NegotiatedParameters;       /* 04h */
+    U32                     Information;                /* 08h */
+} fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
+  SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
+
+#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x03)
+
+#define MPI_SCSIDEVPAGE0_NP_IU                          (0x00000001)
+#define MPI_SCSIDEVPAGE0_NP_DT                          (0x00000002)
+#define MPI_SCSIDEVPAGE0_NP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE0_NP_HOLD_MCS                    (0x00000008)
+#define MPI_SCSIDEVPAGE0_NP_WR_FLOW                     (0x00000010)
+#define MPI_SCSIDEVPAGE0_NP_RD_STRM                     (0x00000020)
+#define MPI_SCSIDEVPAGE0_NP_RTI                         (0x00000040)
+#define MPI_SCSIDEVPAGE0_NP_PCOMP_EN                    (0x00000080)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
+#define MPI_SCSIDEVPAGE0_NP_AIP                         (0x80000000)
+
+#define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED         (0x00000001)
+#define MPI_SCSIDEVPAGE0_INFO_SDTR_REJECTED             (0x00000002)
+#define MPI_SCSIDEVPAGE0_INFO_WDTR_REJECTED             (0x00000004)
+#define MPI_SCSIDEVPAGE0_INFO_PPR_REJECTED              (0x00000008)
+
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     RequestedParameters;        /* 04h */
+    U32                     Reserved;                   /* 08h */
+    U32                     Configuration;              /* 0Ch */
+} fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
+  SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
+
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x04)
+
+#define MPI_SCSIDEVPAGE1_RP_IU                          (0x00000001)
+#define MPI_SCSIDEVPAGE1_RP_DT                          (0x00000002)
+#define MPI_SCSIDEVPAGE1_RP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE1_RP_HOLD_MCS                    (0x00000008)
+#define MPI_SCSIDEVPAGE1_RP_WR_FLOW                     (0x00000010)
+#define MPI_SCSIDEVPAGE1_RP_RD_STRM                     (0x00000020)
+#define MPI_SCSIDEVPAGE1_RP_RTI                         (0x00000040)
+#define MPI_SCSIDEVPAGE1_RP_PCOMP_EN                    (0x00000080)
+#define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK        (0x0000FF00)
+#define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK        (0x00FF0000)
+#define MPI_SCSIDEVPAGE1_RP_WIDE                        (0x20000000)
+#define MPI_SCSIDEVPAGE1_RP_AIP                         (0x80000000)
+
+#define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED           (0x00000002)
+#define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED           (0x00000004)
+#define MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE    (0x00000008)
+#define MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG             (0x00000010)
+
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     DomainValidation;           /* 04h */
+    U32                     ParityPipeSelect;           /* 08h */
+    U32                     DataPipeSelect;             /* 0Ch */
+} fCONFIG_PAGE_SCSI_DEVICE_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_2,
+  SCSIDevicePage2_t, MPI_POINTER pSCSIDevicePage2_t;
+
+#define MPI_SCSIDEVPAGE2_PAGEVERSION                    (0x01)
+
+#define MPI_SCSIDEVPAGE2_DV_ISI_ENABLE                  (0x00000010)
+#define MPI_SCSIDEVPAGE2_DV_SECONDARY_DRIVER_ENABLE     (0x00000020)
+#define MPI_SCSIDEVPAGE2_DV_SLEW_RATE_CTRL              (0x00000380)
+#define MPI_SCSIDEVPAGE2_DV_PRIM_DRIVE_STR_CTRL         (0x00001C00)
+#define MPI_SCSIDEVPAGE2_DV_SECOND_DRIVE_STR_CTRL       (0x0000E000)
+#define MPI_SCSIDEVPAGE2_DV_XCLKH_ST                    (0x10000000)
+#define MPI_SCSIDEVPAGE2_DV_XCLKS_ST                    (0x20000000)
+#define MPI_SCSIDEVPAGE2_DV_XCLKH_DT                    (0x40000000)
+#define MPI_SCSIDEVPAGE2_DV_XCLKS_DT                    (0x80000000)
+
+#define MPI_SCSIDEVPAGE2_PPS_PPS_MASK                   (0x00000003)
+
+#define MPI_SCSIDEVPAGE2_DPS_BIT_0_PL_SELECT_MASK       (0x00000003)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_1_PL_SELECT_MASK       (0x0000000C)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_2_PL_SELECT_MASK       (0x00000030)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_3_PL_SELECT_MASK       (0x000000C0)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_4_PL_SELECT_MASK       (0x00000300)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_5_PL_SELECT_MASK       (0x00000C00)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_6_PL_SELECT_MASK       (0x00003000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_7_PL_SELECT_MASK       (0x0000C000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_8_PL_SELECT_MASK       (0x00030000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_9_PL_SELECT_MASK       (0x000C0000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_10_PL_SELECT_MASK      (0x00300000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_11_PL_SELECT_MASK      (0x00C00000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_12_PL_SELECT_MASK      (0x03000000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_13_PL_SELECT_MASK      (0x0C000000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_14_PL_SELECT_MASK      (0x30000000)
+#define MPI_SCSIDEVPAGE2_DPS_BIT_15_PL_SELECT_MASK      (0xC0000000)
+
+
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_3
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U16                     MsgRejectCount;             /* 04h */
+    U16                     PhaseErrorCount;            /* 06h */
+    U16                     ParityErrorCount;           /* 08h */
+    U16                     Reserved;                   /* 0Ah */
+} fCONFIG_PAGE_SCSI_DEVICE_3, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_3,
+  SCSIDevicePage3_t, MPI_POINTER pSCSIDevicePage3_t;
+
+#define MPI_SCSIDEVPAGE3_PAGEVERSION                    (0x00)
+
+#define MPI_SCSIDEVPAGE3_MAX_COUNTER                    (0xFFFE)
+#define MPI_SCSIDEVPAGE3_UNSUPPORTED_COUNTER            (0xFFFF)
+
+
+/****************************************************************************
+*   FC Port Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_PORT_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Flags;                      /* 04h */
+    U8                      MPIPortNumber;              /* 08h */
+    U8                      LinkType;                   /* 09h */
+    U8                      PortState;                  /* 0Ah */
+    U8                      Reserved;                   /* 0Bh */
+    U32                     PortIdentifier;             /* 0Ch */
+    U64                     WWNN;                       /* 10h */
+    U64                     WWPN;                       /* 18h */
+    U32                     SupportedServiceClass;      /* 20h */
+    U32                     SupportedSpeeds;            /* 24h */
+    U32                     CurrentSpeed;               /* 28h */
+    U32                     MaxFrameSize;               /* 2Ch */
+    U64                     FabricWWNN;                 /* 30h */
+    U64                     FabricWWPN;                 /* 38h */
+    U32                     DiscoveredPortsCount;       /* 40h */
+    U32                     MaxInitiators;              /* 44h */
+    U8                      MaxAliasesSupported;        /* 48h */
+    U8                      MaxHardAliasesSupported;    /* 49h */
+    U8                      NumCurrentAliases;          /* 4Ah */
+    U8                      Reserved1;                  /* 4Bh */
+} fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0,
+  FCPortPage0_t, MPI_POINTER pFCPortPage0_t;
+
+#define MPI_FCPORTPAGE0_PAGEVERSION                     (0x02)
+
+#define MPI_FCPORTPAGE0_FLAGS_PROT_MASK                 (0x0000000F)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT             (MPI_PORTFACTS_PROTOCOL_INITIATOR)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_TARG             (MPI_PORTFACTS_PROTOCOL_TARGET)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LAN                  (MPI_PORTFACTS_PROTOCOL_LAN)
+#define MPI_FCPORTPAGE0_FLAGS_PROT_LOGBUSADDR           (MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)
+
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED      (0x00000010)
+#define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED       (0x00000020)
+#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID          (0x00000030)
+
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK          (0x00000F00)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT            (0x00000000)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT     (0x00000100)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP       (0x00000200)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT      (0x00000400)
+#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP        (0x00000800)
+
+#define MPI_FCPORTPAGE0_LTYPE_RESERVED                  (0x00)
+#define MPI_FCPORTPAGE0_LTYPE_OTHER                     (0x01)
+#define MPI_FCPORTPAGE0_LTYPE_UNKNOWN                   (0x02)
+#define MPI_FCPORTPAGE0_LTYPE_COPPER                    (0x03)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1300               (0x04)
+#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1500               (0x05)
+#define MPI_FCPORTPAGE0_LTYPE_50_LASER_MULTI            (0x06)
+#define MPI_FCPORTPAGE0_LTYPE_50_LED_MULTI              (0x07)
+#define MPI_FCPORTPAGE0_LTYPE_62_LASER_MULTI            (0x08)
+#define MPI_FCPORTPAGE0_LTYPE_62_LED_MULTI              (0x09)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_LONG_WAVE           (0x0A)
+#define MPI_FCPORTPAGE0_LTYPE_MULTI_SHORT_WAVE          (0x0B)
+#define MPI_FCPORTPAGE0_LTYPE_LASER_SHORT_WAVE          (0x0C)
+#define MPI_FCPORTPAGE0_LTYPE_LED_SHORT_WAVE            (0x0D)
+#define MPI_FCPORTPAGE0_LTYPE_1300_LONG_WAVE            (0x0E)
+#define MPI_FCPORTPAGE0_LTYPE_1500_LONG_WAVE            (0x0F)
+
+#define MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN               (0x01)      /*(SNIA)HBA_PORTSTATE_UNKNOWN       1 Unknown */
+#define MPI_FCPORTPAGE0_PORTSTATE_ONLINE                (0x02)      /*(SNIA)HBA_PORTSTATE_ONLINE        2 Operational */
+#define MPI_FCPORTPAGE0_PORTSTATE_OFFLINE               (0x03)      /*(SNIA)HBA_PORTSTATE_OFFLINE       3 User Offline */
+#define MPI_FCPORTPAGE0_PORTSTATE_BYPASSED              (0x04)      /*(SNIA)HBA_PORTSTATE_BYPASSED      4 Bypassed */
+#define MPI_FCPORTPAGE0_PORTSTATE_DIAGNOST              (0x05)      /*(SNIA)HBA_PORTSTATE_DIAGNOSTICS   5 In diagnostics mode */
+#define MPI_FCPORTPAGE0_PORTSTATE_LINKDOWN              (0x06)      /*(SNIA)HBA_PORTSTATE_LINKDOWN      6 Link Down */
+#define MPI_FCPORTPAGE0_PORTSTATE_ERROR                 (0x07)      /*(SNIA)HBA_PORTSTATE_ERROR         7 Port Error */
+#define MPI_FCPORTPAGE0_PORTSTATE_LOOPBACK              (0x08)      /*(SNIA)HBA_PORTSTATE_LOOPBACK      8 Loopback */
+
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_1                 (0x00000001)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_2                 (0x00000002)
+#define MPI_FCPORTPAGE0_SUPPORT_CLASS_3                 (0x00000004)
+
+#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED             (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1  1 GBit/sec  */
+#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED             (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2  2 GBit/sec  */
+#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED            (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */
+
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT             MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT             MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED
+#define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT            MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_1
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Flags;                      /* 04h */
+    U64                     NoSEEPROMWWNN;              /* 08h */
+    U64                     NoSEEPROMWWPN;              /* 10h */
+    U8                      HardALPA;                   /* 18h */
+    U8                      LinkConfig;                 /* 19h */
+    U8                      TopologyConfig;             /* 1Ah */
+    U8                      AltConnector;               /* 1Bh */
+    U8                      NumRequestedAliases;        /* 1Ch */
+    U8                      Reserved1;                  /* 1Dh */
+    U16                     Reserved2;                  /* 1Eh */
+} fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
+  FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
+
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x04)
+
+#define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
+#define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID               (0x00000001)
+#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN               (0x00000000)
+
+#define MPI_FCPORTPAGE1_FLAGS_PROT_MASK                 (0xF0000000)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT                (28)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT             ((U32)MPI_PORTFACTS_PROTOCOL_INITIATOR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG             ((U32)MPI_PORTFACTS_PROTOCOL_TARGET << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LAN                  ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+#define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR           ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT)
+
+#define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED              (0xFF)
+
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK              (0x0F)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG              (0x00)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG              (0x01)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG              (0x02)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG             (0x03)
+#define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO              (0x0F)
+
+#define MPI_FCPORTPAGE1_TOPOLOGY_MASK                   (0x0F)
+#define MPI_FCPORTPAGE1_TOPOLOGY_NLPORT                 (0x01)
+#define MPI_FCPORTPAGE1_TOPOLOGY_NPORT                  (0x02)
+#define MPI_FCPORTPAGE1_TOPOLOGY_AUTO                   (0x0F)
+
+#define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN                (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_2
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U8                      NumberActive;               /* 04h */
+    U8                      ALPA[127];                  /* 05h */
+} fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2,
+  FCPortPage2_t, MPI_POINTER pFCPortPage2_t;
+
+#define MPI_FCPORTPAGE2_PAGEVERSION                     (0x01)
+
+
+typedef struct _WWN_FORMAT
+{
+    U64                     WWNN;                       /* 00h */
+    U64                     WWPN;                       /* 08h */
+} WWN_FORMAT, MPI_POINTER PTR_WWN_FORMAT,
+  WWNFormat, MPI_POINTER pWWNFormat;
+
+typedef union _FC_PORT_PERSISTENT_PHYSICAL_ID
+{
+    WWN_FORMAT              WWN;
+    U32                     Did;
+} FC_PORT_PERSISTENT_PHYSICAL_ID, MPI_POINTER PTR_FC_PORT_PERSISTENT_PHYSICAL_ID,
+  PersistentPhysicalId_t, MPI_POINTER pPersistentPhysicalId_t;
+
+typedef struct _FC_PORT_PERSISTENT
+{
+    FC_PORT_PERSISTENT_PHYSICAL_ID  PhysicalIdentifier; /* 00h */
+    U8                              TargetID;           /* 10h */
+    U8                              Bus;                /* 11h */
+    U16                             Flags;              /* 12h */
+} FC_PORT_PERSISTENT, MPI_POINTER PTR_FC_PORT_PERSISTENT,
+  PersistentData_t, MPI_POINTER pPersistentData_t;
+
+#define MPI_PERSISTENT_FLAGS_SHIFT                      (16)
+#define MPI_PERSISTENT_FLAGS_ENTRY_VALID                (0x0001)
+#define MPI_PERSISTENT_FLAGS_SCAN_ID                    (0x0002)
+#define MPI_PERSISTENT_FLAGS_SCAN_LUNS                  (0x0004)
+#define MPI_PERSISTENT_FLAGS_BOOT_DEVICE                (0x0008)
+#define MPI_PERSISTENT_FLAGS_BY_DID                     (0x0080)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_FC_PORT_PAGE_3_ENTRY_MAX
+#define MPI_FC_PORT_PAGE_3_ENTRY_MAX        (1)
+#endif
+
+typedef struct _CONFIG_PAGE_FC_PORT_3
+{
+    fCONFIG_PAGE_HEADER      Header;                                 /* 00h */
+    FC_PORT_PERSISTENT      Entry[MPI_FC_PORT_PAGE_3_ENTRY_MAX];    /* 04h */
+} fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3,
+  FCPortPage3_t, MPI_POINTER pFCPortPage3_t;
+
+#define MPI_FCPORTPAGE3_PAGEVERSION                     (0x01)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_4
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     PortFlags;                  /* 04h */
+    U32                     PortSettings;               /* 08h */
+} fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4,
+  FCPortPage4_t, MPI_POINTER pFCPortPage4_t;
+
+#define MPI_FCPORTPAGE4_PAGEVERSION                     (0x00)
+
+#define MPI_FCPORTPAGE4_PORT_FLAGS_ALTERNATE_CHS        (0x00000008)
+
+#define MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA              (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA           (0x00000000)
+#define MPI_FCPORTPAGE4_PORT_BIOS_INIT_HBA              (0x00000010)
+#define MPI_FCPORTPAGE4_PORT_OS_INIT_HBA                (0x00000020)
+#define MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA           (0x00000030)
+#define MPI_FCPORTPAGE4_PORT_REMOVABLE_MEDIA            (0x000000C0)
+#define MPI_FCPORTPAGE4_PORT_SPINUP_DELAY_MASK          (0x00000F00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO
+{
+    U8      Flags;                                      /* 00h */
+    U8      AliasAlpa;                                  /* 01h */
+    U16     Reserved;                                   /* 02h */
+    U64     AliasWWNN;                                  /* 04h */
+    U64     AliasWWPN;                                  /* 0Ch */
+} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
+  FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
+
+typedef struct _CONFIG_PAGE_FC_PORT_5
+{
+    fCONFIG_PAGE_HEADER                  Header;         /* 00h */
+    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo;      /* 04h */
+} fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5,
+  FCPortPage5_t, MPI_POINTER pFCPortPage5_t;
+
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x01)
+
+#define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED             (0x01)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA                 (0x02)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN                 (0x04)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN                 (0x08)
+
+typedef struct _CONFIG_PAGE_FC_PORT_6
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Reserved;                   /* 04h */
+    U64                     TimeSinceReset;             /* 08h */
+    U64                     TxFrames;                   /* 10h */
+    U64                     RxFrames;                   /* 18h */
+    U64                     TxWords;                    /* 20h */
+    U64                     RxWords;                    /* 28h */
+    U64                     LipCount;                   /* 30h */
+    U64                     NosCount;                   /* 38h */
+    U64                     ErrorFrames;                /* 40h */
+    U64                     DumpedFrames;               /* 48h */
+    U64                     LinkFailureCount;           /* 50h */
+    U64                     LossOfSyncCount;            /* 58h */
+    U64                     LossOfSignalCount;          /* 60h */
+    U64                     PrimativeSeqErrCount;       /* 68h */
+    U64                     InvalidTxWordCount;         /* 70h */
+    U64                     InvalidCrcCount;            /* 78h */
+    U64                     FcpInitiatorIoCount;        /* 80h */
+} fCONFIG_PAGE_FC_PORT_6, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_6,
+  FCPortPage6_t, MPI_POINTER pFCPortPage6_t;
+
+#define MPI_FCPORTPAGE6_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_7
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Reserved;                   /* 04h */
+    U8                      PortSymbolicName[256];      /* 08h */
+} fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7,
+  FCPortPage7_t, MPI_POINTER pFCPortPage7_t;
+
+#define MPI_FCPORTPAGE7_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_8
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     BitVector[8];               /* 04h */
+} fCONFIG_PAGE_FC_PORT_8, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_8,
+  FCPortPage8_t, MPI_POINTER pFCPortPage8_t;
+
+#define MPI_FCPORTPAGE8_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_9
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U32                     Reserved;                   /* 04h */
+    U64                     GlobalWWPN;                 /* 08h */
+    U64                     GlobalWWNN;                 /* 10h */
+    U32                     UnitType;                   /* 18h */
+    U32                     PhysicalPortNumber;         /* 1Ch */
+    U32                     NumAttachedNodes;           /* 20h */
+    U16                     IPVersion;                  /* 24h */
+    U16                     UDPPortNumber;              /* 26h */
+    U8                      IPAddress[16];              /* 28h */
+    U16                     Reserved1;                  /* 38h */
+    U16                     TopologyDiscoveryFlags;     /* 3Ah */
+} fCONFIG_PAGE_FC_PORT_9, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_9,
+  FCPortPage9_t, MPI_POINTER pFCPortPage9_t;
+
+#define MPI_FCPORTPAGE9_PAGEVERSION                     (0x00)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA
+{
+    U8                      Id;                         /* 10h */
+    U8                      ExtId;                      /* 11h */
+    U8                      Connector;                  /* 12h */
+    U8                      Transceiver[8];             /* 13h */
+    U8                      Encoding;                   /* 1Bh */
+    U8                      BitRate_100mbs;             /* 1Ch */
+    U8                      Reserved1;                  /* 1Dh */
+    U8                      Length9u_km;                /* 1Eh */
+    U8                      Length9u_100m;              /* 1Fh */
+    U8                      Length50u_10m;              /* 20h */
+    U8                      Length62p5u_10m;            /* 21h */
+    U8                      LengthCopper_m;             /* 22h */
+    U8                      Reseverved2;                /* 22h */
+    U8                      VendorName[16];             /* 24h */
+    U8                      Reserved3;                  /* 34h */
+    U8                      VendorOUI[3];               /* 35h */
+    U8                      VendorPN[16];               /* 38h */
+    U8                      VendorRev[4];               /* 48h */
+    U16                     Reserved4;                  /* 4Ch */
+    U8                      Reserved5;                  /* 4Eh */
+    U8                      CC_BASE;                    /* 4Fh */
+} fCONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA,
+  FCPortPage10BaseSfpData_t, MPI_POINTER pFCPortPage10BaseSfpData_t;
+
+#define MPI_FCPORT10_BASE_ID_UNKNOWN        (0x00)
+#define MPI_FCPORT10_BASE_ID_GBIC           (0x01)
+#define MPI_FCPORT10_BASE_ID_FIXED          (0x02)
+#define MPI_FCPORT10_BASE_ID_SFP            (0x03)
+#define MPI_FCPORT10_BASE_ID_SFP_MIN        (0x04)
+#define MPI_FCPORT10_BASE_ID_SFP_MAX        (0x7F)
+#define MPI_FCPORT10_BASE_ID_VEND_SPEC_MASK (0x80)
+
+#define MPI_FCPORT10_BASE_EXTID_UNKNOWN     (0x00)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF1     (0x01)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF2     (0x02)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF3     (0x03)
+#define MPI_FCPORT10_BASE_EXTID_SEEPROM     (0x04)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF5     (0x05)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF6     (0x06)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF7     (0x07)
+#define MPI_FCPORT10_BASE_EXTID_VNDSPC_MASK (0x80)
+
+#define MPI_FCPORT10_BASE_CONN_UNKNOWN      (0x00)
+#define MPI_FCPORT10_BASE_CONN_SC           (0x01)
+#define MPI_FCPORT10_BASE_CONN_COPPER1      (0x02)
+#define MPI_FCPORT10_BASE_CONN_COPPER2      (0x03)
+#define MPI_FCPORT10_BASE_CONN_BNC_TNC      (0x04)
+#define MPI_FCPORT10_BASE_CONN_COAXIAL      (0x05)
+#define MPI_FCPORT10_BASE_CONN_FIBERJACK    (0x06)
+#define MPI_FCPORT10_BASE_CONN_LC           (0x07)
+#define MPI_FCPORT10_BASE_CONN_MT_RJ        (0x08)
+#define MPI_FCPORT10_BASE_CONN_MU           (0x09)
+#define MPI_FCPORT10_BASE_CONN_SG           (0x0A)
+#define MPI_FCPORT10_BASE_CONN_OPT_PIGT     (0x0B)
+#define MPI_FCPORT10_BASE_CONN_RSV1_MIN     (0x0C)
+#define MPI_FCPORT10_BASE_CONN_RSV1_MAX     (0x1F)
+#define MPI_FCPORT10_BASE_CONN_HSSDC_II     (0x20)
+#define MPI_FCPORT10_BASE_CONN_CPR_PIGT     (0x21)
+#define MPI_FCPORT10_BASE_CONN_RSV2_MIN     (0x22)
+#define MPI_FCPORT10_BASE_CONN_RSV2_MAX     (0x7F)
+#define MPI_FCPORT10_BASE_CONN_VNDSPC_MASK  (0x80)
+
+#define MPI_FCPORT10_BASE_ENCODE_UNSPEC     (0x00)
+#define MPI_FCPORT10_BASE_ENCODE_8B10B      (0x01)
+#define MPI_FCPORT10_BASE_ENCODE_4B5B       (0x02)
+#define MPI_FCPORT10_BASE_ENCODE_NRZ        (0x03)
+#define MPI_FCPORT10_BASE_ENCODE_MANCHESTER (0x04)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA
+{
+    U8                      Options[2];                 /* 50h */
+    U8                      BitRateMax;                 /* 52h */
+    U8                      BitRateMin;                 /* 53h */
+    U8                      VendorSN[16];               /* 54h */
+    U8                      DateCode[8];                /* 64h */
+    U8                      Reserved5[3];               /* 6Ch */
+    U8                      CC_EXT;                     /* 6Fh */
+} fCONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA,
+  FCPortPage10ExtendedSfpData_t, MPI_POINTER pFCPortPage10ExtendedSfpData_t;
+
+#define MPI_FCPORT10_EXT_OPTION1_RATESEL    (0x20)
+#define MPI_FCPORT10_EXT_OPTION1_TX_DISABLE (0x10)
+#define MPI_FCPORT10_EXT_OPTION1_TX_FAULT   (0x08)
+#define MPI_FCPORT10_EXT_OPTION1_LOS_INVERT (0x04)
+#define MPI_FCPORT10_EXT_OPTION1_LOS        (0x02)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10
+{
+    fCONFIG_PAGE_HEADER                          Header;             /* 00h */
+    U8                                          Flags;              /* 04h */
+    U8                                          Reserved1;          /* 05h */
+    U16                                         Reserved2;          /* 06h */
+    U32                                         HwConfig1;          /* 08h */
+    U32                                         HwConfig2;          /* 0Ch */
+    fCONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA        Base;               /* 10h */
+    fCONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA    Extended;           /* 50h */
+    U8                                          VendorSpecific[32]; /* 70h */
+} fCONFIG_PAGE_FC_PORT_10, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10,
+  FCPortPage10_t, MPI_POINTER pFCPortPage10_t;
+
+#define MPI_FCPORTPAGE10_PAGEVERSION                    (0x00)
+
+/* standard MODDEF pin definitions (from GBIC spec.) */
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_MASK              (0x00000007)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF2                  (0x00000001)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF1                  (0x00000002)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF0                  (0x00000004)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_NOGBIC            (0x00000007)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_CPR_IEEE_CX       (0x00000006)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_COPPER            (0x00000005)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_OPTICAL_LW        (0x00000004)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SEEPROM           (0x00000003)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SW_OPTICAL        (0x00000002)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_LX_IEEE_OPT_LW    (0x00000001)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SX_IEEE_OPT_SW    (0x00000000)
+
+#define MPI_FCPORTPAGE10_FLAGS_CC_BASE_OK               (0x00000010)
+#define MPI_FCPORTPAGE10_FLAGS_CC_EXT_OK                (0x00000020)
+
+
+/****************************************************************************
+*   FC Device Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_FC_DEVICE_0
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U64                     WWNN;                       /* 04h */
+    U64                     WWPN;                       /* 0Ch */
+    U32                     PortIdentifier;             /* 14h */
+    U8                      Protocol;                   /* 18h */
+    U8                      Flags;                      /* 19h */
+    U16                     BBCredit;                   /* 1Ah */
+    U16                     MaxRxFrameSize;             /* 1Ch */
+    U8                      Reserved1;                  /* 1Eh */
+    U8                      PortNumber;                 /* 1Fh */
+    U8                      FcPhLowestVersion;          /* 20h */
+    U8                      FcPhHighestVersion;         /* 21h */
+    U8                      CurrentTargetID;            /* 22h */
+    U8                      CurrentBus;                 /* 23h */
+} fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0,
+  FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t;
+
+#define MPI_FC_DEVICE_PAGE0_PAGEVERSION                 (0x02)
+
+#define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID    (0x01)
+
+#define MPI_FC_DEVICE_PAGE0_PROT_IP                     (0x01)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET             (0x02)
+#define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR          (0x04)
+
+#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK      (MPI_FC_DEVICE_PGAD_PORT_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK      (MPI_FC_DEVICE_PGAD_FORM_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID  (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID   (MPI_FC_DEVICE_PGAD_FORM_BUS_TID)
+#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK       (MPI_FC_DEVICE_PGAD_ND_DID_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK       (MPI_FC_DEVICE_PGAD_BT_BUS_MASK)
+#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT      (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT)
+#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK       (MPI_FC_DEVICE_PGAD_BT_TID_MASK)
+
+
+/****************************************************************************
+*   RAID Volume Config Pages
+****************************************************************************/
+
+typedef struct _RAID_VOL0_PHYS_DISK
+{
+    U16                         Reserved;               /* 00h */
+    U8                          PhysDiskMap;            /* 02h */
+    U8                          PhysDiskNum;            /* 03h */
+} RAID_VOL0_PHYS_DISK, MPI_POINTER PTR_RAID_VOL0_PHYS_DISK,
+  RaidVol0PhysDisk_t, MPI_POINTER pRaidVol0PhysDisk_t;
+
+#define MPI_RAIDVOL0_PHYSDISK_PRIMARY                   (0x01)
+#define MPI_RAIDVOL0_PHYSDISK_SECONDARY                 (0x02)
+
+typedef struct _RAID_VOL0_STATUS
+{
+    U8                          Flags;                  /* 00h */
+    U8                          State;                  /* 01h */
+    U16                         Reserved;               /* 02h */
+} RAID_VOL0_STATUS, MPI_POINTER PTR_RAID_VOL0_STATUS,
+  RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t;
+
+/* RAID Volume Page 0 VolumeStatus defines */
+
+#define MPI_RAIDVOL0_STATUS_FLAG_ENABLED                (0x01)
+#define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED               (0x02)
+#define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS     (0x04)
+#define MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE        (0x08)
+
+#define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL               (0x00)
+#define MPI_RAIDVOL0_STATUS_STATE_DEGRADED              (0x01)
+#define MPI_RAIDVOL0_STATUS_STATE_FAILED                (0x02)
+
+typedef struct _RAID_VOL0_SETTINGS
+{
+    U16                         Settings;       /* 00h */
+    U8                          HotSparePool;   /* 01h */ /* MPI_RAID_HOT_SPARE_POOL_ */
+    U8                          Reserved;       /* 02h */
+} RAID_VOL0_SETTINGS, MPI_POINTER PTR_RAID_VOL0_SETTINGS,
+  RaidVol0Settings, MPI_POINTER pRaidVol0Settings;
+
+/* RAID Volume Page 0 VolumeSettings defines */
+
+#define MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE       (0x0001)
+#define MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART           (0x0002)
+#define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE             (0x0004)
+#define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC            (0x0008)
+#define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX      (0x0010)
+#define MPI_RAIDVOL0_SETTING_USE_DEFAULTS               (0x8000)
+
+/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
+#define MPI_RAID_HOT_SPARE_POOL_0                       (0x01)
+#define MPI_RAID_HOT_SPARE_POOL_1                       (0x02)
+#define MPI_RAID_HOT_SPARE_POOL_2                       (0x04)
+#define MPI_RAID_HOT_SPARE_POOL_3                       (0x08)
+#define MPI_RAID_HOT_SPARE_POOL_4                       (0x10)
+#define MPI_RAID_HOT_SPARE_POOL_5                       (0x20)
+#define MPI_RAID_HOT_SPARE_POOL_6                       (0x40)
+#define MPI_RAID_HOT_SPARE_POOL_7                       (0x80)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX
+#define MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX        (1)
+#endif
+
+typedef struct _CONFIG_PAGE_RAID_VOL_0
+{
+    fCONFIG_PAGE_HEADER      Header;         /* 00h */
+    U8                      VolumeID;       /* 04h */
+    U8                      VolumeBus;      /* 05h */
+    U8                      VolumeIOC;      /* 06h */
+    U8                      VolumeType;     /* 07h */ /* MPI_RAID_VOL_TYPE_ */
+    RAID_VOL0_STATUS        VolumeStatus;   /* 08h */
+    RAID_VOL0_SETTINGS      VolumeSettings; /* 0Ch */
+    U32                     MaxLBA;         /* 10h */
+    U32                     Reserved1;      /* 14h */
+    U32                     StripeSize;     /* 18h */
+    U32                     Reserved2;      /* 1Ch */
+    U32                     Reserved3;      /* 20h */
+    U8                      NumPhysDisks;   /* 24h */
+    U8                      Reserved4;      /* 25h */
+    U16                     Reserved5;      /* 26h */
+    RAID_VOL0_PHYS_DISK     PhysDisk[MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX];/* 28h */
+} fCONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
+  RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
+
+#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x01)
+
+
+/****************************************************************************
+*   RAID Physical Disk Config Pages
+****************************************************************************/
+
+typedef struct _RAID_PHYS_DISK0_ERROR_DATA
+{
+    U8                      ErrorCdbByte;               /* 00h */
+    U8                      ErrorSenseKey;              /* 01h */
+    U16                     Reserved;                   /* 02h */
+    U16                     ErrorCount;                 /* 04h */
+    U8                      ErrorASC;                   /* 06h */
+    U8                      ErrorASCQ;                  /* 07h */
+    U16                     SmartCount;                 /* 08h */
+    U8                      SmartASC;                   /* 0Ah */
+    U8                      SmartASCQ;                  /* 0Bh */
+} RAID_PHYS_DISK0_ERROR_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_ERROR_DATA,
+  RaidPhysDisk0ErrorData_t, MPI_POINTER pRaidPhysDisk0ErrorData_t;
+
+typedef struct _RAID_PHYS_DISK_INQUIRY_DATA
+{
+    U8                          VendorID[8];            /* 00h */
+    U8                          ProductID[16];          /* 08h */
+    U8                          ProductRevLevel[4];     /* 18h */
+    U8                          Info[32];               /* 1Ch */
+} RAID_PHYS_DISK0_INQUIRY_DATA, MPI_POINTER PTR_RAID_PHYS_DISK0_INQUIRY_DATA,
+  RaidPhysDisk0InquiryData, MPI_POINTER pRaidPhysDisk0InquiryData;
+
+typedef struct _RAID_PHYS_DISK0_SETTINGS
+{
+    U8              SepID;              /* 00h */
+    U8              SepBus;             /* 01h */
+    U8              HotSparePool;       /* 02h */ /* MPI_RAID_HOT_SPARE_POOL_ */
+    U8              PhysDiskSettings;   /* 03h */
+} RAID_PHYS_DISK0_SETTINGS, MPI_POINTER PTR_RAID_PHYS_DISK0_SETTINGS,
+  RaidPhysDiskSettings_t, MPI_POINTER pRaidPhysDiskSettings_t;
+
+typedef struct _RAID_PHYS_DISK0_STATUS
+{
+    U8                              Flags;              /* 00h */
+    U8                              State;              /* 01h */
+    U16                             Reserved;           /* 02h */
+} RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS,
+  RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t;
+
+/* RAID Volume 2 IM Physical Disk DiskStatus flags */
+
+#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC           (0x01)
+#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED              (0x02)
+
+#define MPI_PHYSDISK0_STATUS_ONLINE                     (0x00)
+#define MPI_PHYSDISK0_STATUS_MISSING                    (0x01)
+#define MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE             (0x02)
+#define MPI_PHYSDISK0_STATUS_FAILED                     (0x03)
+#define MPI_PHYSDISK0_STATUS_INITIALIZING               (0x04)
+#define MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED          (0x05)
+#define MPI_PHYSDISK0_STATUS_FAILED_REQUESTED           (0x06)
+#define MPI_PHYSDISK0_STATUS_OTHER_OFFLINE              (0xFF)
+
+typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0
+{
+    fCONFIG_PAGE_HEADER              Header;             /* 00h */
+    U8                              PhysDiskID;         /* 04h */
+    U8                              PhysDiskBus;        /* 05h */
+    U8                              PhysDiskIOC;        /* 06h */
+    U8                              PhysDiskNum;        /* 07h */
+    RAID_PHYS_DISK0_SETTINGS        PhysDiskSettings;   /* 08h */
+    U32                             Reserved1;          /* 0Ch */
+    U32                             Reserved2;          /* 10h */
+    U32                             Reserved3;          /* 14h */
+    U8                              DiskIdentifier[16]; /* 18h */
+    RAID_PHYS_DISK0_INQUIRY_DATA    InquiryData;        /* 28h */
+    RAID_PHYS_DISK0_STATUS          PhysDiskStatus;     /* 64h */
+    U32                             MaxLBA;             /* 68h */
+    RAID_PHYS_DISK0_ERROR_DATA      ErrorData;          /* 6Ch */
+} fCONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0,
+  RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t;
+
+#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION           (0x00)
+
+
+/****************************************************************************
+*   LAN Config Pages
+****************************************************************************/
+
+typedef struct _CONFIG_PAGE_LAN_0
+{
+    ConfigPageHeader_t      Header;                     /* 00h */
+    U16                     TxRxModes;                  /* 04h */
+    U16                     Reserved;                   /* 06h */
+    U32                     PacketPrePad;               /* 08h */
+} fCONFIG_PAGE_LAN_0, MPI_POINTER PTR_CONFIG_PAGE_LAN_0,
+  LANPage0_t, MPI_POINTER pLANPage0_t;
+
+#define MPI_LAN_PAGE0_PAGEVERSION                       (0x01)
+
+#define MPI_LAN_PAGE0_RETURN_LOOPBACK                   (0x0000)
+#define MPI_LAN_PAGE0_SUPPRESS_LOOPBACK                 (0x0001)
+#define MPI_LAN_PAGE0_LOOPBACK_MASK                     (0x0001)
+
+typedef struct _CONFIG_PAGE_LAN_1
+{
+    ConfigPageHeader_t      Header;                     /* 00h */
+    U16                     Reserved;                   /* 04h */
+    U8                      CurrentDeviceState;         /* 06h */
+    U8                      Reserved1;                  /* 07h */
+    U32                     MinPacketSize;              /* 08h */
+    U32                     MaxPacketSize;              /* 0Ch */
+    U32                     HardwareAddressLow;         /* 10h */
+    U32                     HardwareAddressHigh;        /* 14h */
+    U32                     MaxWireSpeedLow;            /* 18h */
+    U32                     MaxWireSpeedHigh;           /* 1Ch */
+    U32                     BucketsRemaining;           /* 20h */
+    U32                     MaxReplySize;               /* 24h */
+    U32                     NegWireSpeedLow;            /* 28h */
+    U32                     NegWireSpeedHigh;           /* 2Ch */
+} fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1,
+  LANPage1_t, MPI_POINTER pLANPage1_t;
+
+#define MPI_LAN_PAGE1_PAGEVERSION                       (0x03)
+
+#define MPI_LAN_PAGE1_DEV_STATE_RESET                   (0x00)
+#define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL             (0x01)
+
+#endif
+
diff --git a/xen/drivers/message/fusion/lsi/mpi_fc.h b/xen/drivers/message/fusion/lsi/mpi_fc.h
new file mode 100644 (file)
index 0000000..7873657
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_FC.H
+ *          Title:  MPI Fibre Channel messages and structures
+ *  Creation Date:  June 12, 2000
+ *
+ *    MPI_FC.H Version:  01.02.03
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added _MSG_FC_ABORT_REPLY structure.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added messages for Common Transport Send and
+ *                      Primitive Send.
+ *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *                      and modified the FcPrimitiveSend flags.
+ *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
+ *                      field.
+ *                      Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ *                      FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *  03-27-01  01.01.06  Added Flags field to MSG_LINK_SERVICE_BUFFER_POST_REPLY
+ *                      and defined MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_RESET_LINK define.
+ *                      Added structure offset comments.
+ *  04-09-01  01.01.07  Added RspLength field to MSG_LINK_SERVICE_RSP_REQUEST.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Change name of reserved field in
+ *                      MSG_LINK_SERVICE_RSP_REPLY.
+ *  05-31-02  01.02.03  Adding AliasIndex to FC Direct Access requests.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_FC_H
+#define MPI_FC_H
+
+
+/*****************************************************************************
+*
+*        F C    T a r g e t    M o d e    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/* Link Service Buffer Post messages                                        */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REQUEST
+{
+    U8                      BufferPostFlags;    /* 00h */
+    U8                      BufferCount;        /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved;           /* 04h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    SGE_TRANS_SIMPLE_UNION  SGL;
+} MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+ MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REQUEST,
+  LinkServiceBufferPostRequest_t, MPI_POINTER pLinkServiceBufferPostRequest_t;
+
+#define LINK_SERVICE_BUFFER_POST_FLAGS_PORT_MASK (0x01)
+
+typedef struct _WWNFORMAT
+{
+    U32                     PortNameHigh;       /* 00h */
+    U32                     PortNameLow;        /* 04h */
+    U32                     NodeNameHigh;       /* 08h */
+    U32                     NodeNameLow;        /* 0Ch */
+} WWNFORMAT,
+  WwnFormat_t;
+
+/* Link Service Buffer Post Reply */
+typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REPLY
+{
+    U8                      Flags;              /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved2;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferLength;     /* 14h */
+    U32                     TransactionContext; /* 18h */
+    U32                     Rctl_Did;           /* 1Ch */
+    U32                     Csctl_Sid;          /* 20h */
+    U32                     Type_Fctl;          /* 24h */
+    U16                     SeqCnt;             /* 28h */
+    U8                      Dfctl;              /* 2Ah */
+    U8                      SeqId;              /* 2Bh */
+    U16                     Rxid;               /* 2Ch */
+    U16                     Oxid;               /* 2Eh */
+    U32                     Parameter;          /* 30h */
+    WWNFORMAT               Wwn;                /* 34h */
+} MSG_LINK_SERVICE_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY,
+  LinkServiceBufferPostReply_t, MPI_POINTER pLinkServiceBufferPostReply_t;
+
+#define MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED    (0x80)
+
+#define MPI_FC_DID_MASK                             (0x00FFFFFF)
+#define MPI_FC_DID_SHIFT                            (0)
+#define MPI_FC_RCTL_MASK                            (0xFF000000)
+#define MPI_FC_RCTL_SHIFT                           (24)
+#define MPI_FC_SID_MASK                             (0x00FFFFFF)
+#define MPI_FC_SID_SHIFT                            (0)
+#define MPI_FC_CSCTL_MASK                           (0xFF000000)
+#define MPI_FC_CSCTL_SHIFT                          (24)
+#define MPI_FC_FCTL_MASK                            (0x00FFFFFF)
+#define MPI_FC_FCTL_SHIFT                           (0)
+#define MPI_FC_TYPE_MASK                            (0xFF000000)
+#define MPI_FC_TYPE_SHIFT                           (24)
+
+/* obsolete name for the above */
+#define FCP_TARGET_DID_MASK                         (0x00FFFFFF)
+#define FCP_TARGET_DID_SHIFT                        (0)
+#define FCP_TARGET_RCTL_MASK                        (0xFF000000)
+#define FCP_TARGET_RCTL_SHIFT                       (24)
+#define FCP_TARGET_SID_MASK                         (0x00FFFFFF)
+#define FCP_TARGET_SID_SHIFT                        (0)
+#define FCP_TARGET_CSCTL_MASK                       (0xFF000000)
+#define FCP_TARGET_CSCTL_SHIFT                      (24)
+#define FCP_TARGET_FCTL_MASK                        (0x00FFFFFF)
+#define FCP_TARGET_FCTL_SHIFT                       (0)
+#define FCP_TARGET_TYPE_MASK                        (0xFF000000)
+#define FCP_TARGET_TYPE_SHIFT                       (24)
+
+
+/****************************************************************************/
+/* Link Service Response messages                                           */
+/****************************************************************************/
+
+typedef struct _MSG_LINK_SERVICE_RSP_REQUEST
+{
+    U8                      RspFlags;           /* 00h */
+    U8                      RspLength;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Rctl_Did;           /* 0Ch */
+    U32                     Csctl_Sid;          /* 10h */
+    U32                     Type_Fctl;          /* 14h */
+    U16                     SeqCnt;             /* 18h */
+    U8                      Dfctl;              /* 1Ah */
+    U8                      SeqId;              /* 1Bh */
+    U16                     Rxid;               /* 1Ch */
+    U16                     Oxid;               /* 1Eh */
+    U32                     Parameter;          /* 20h */
+    SGE_SIMPLE_UNION        SGL;                /* 24h */
+} MSG_LINK_SERVICE_RSP_REQUEST, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REQUEST,
+  LinkServiceRspRequest_t, MPI_POINTER pLinkServiceRspRequest_t;
+
+#define LINK_SERVICE_RSP_FLAGS_IMMEDIATE        (0x80)
+#define LINK_SERVICE_RSP_FLAGS_PORT_MASK        (0x01)
+
+
+/* Link Service Response Reply  */
+typedef struct _MSG_LINK_SERVICE_RSP_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved_0100_InitiatorIndex; /* 06h */ /* obsolete InitiatorIndex */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     InitiatorIndex;     /* 14h */
+} MSG_LINK_SERVICE_RSP_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REPLY,
+  LinkServiceRspReply_t, MPI_POINTER pLinkServiceRspReply_t;
+
+
+/****************************************************************************/
+/* Extended Link Service Send messages                                      */
+/****************************************************************************/
+
+typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      AliasIndex;         /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U32                     MsgFlags_Did;       /* 04h */
+    U32                     MsgContext;         /* 08h */
+    U32                     ElsCommandCode;     /* 0Ch */
+    SGE_SIMPLE_UNION        SGL;                /* 10h */
+} MSG_EXLINK_SERVICE_SEND_REQUEST, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REQUEST,
+  ExLinkServiceSendRequest_t, MPI_POINTER pExLinkServiceSendRequest_t;
+
+#define EX_LINK_SERVICE_SEND_DID_MASK           (0x00FFFFFF)
+#define EX_LINK_SERVICE_SEND_DID_SHIFT          (0)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_MASK      (0xFF000000)
+#define EX_LINK_SERVICE_SEND_MSGFLAGS_SHIFT     (24)
+
+
+/* Extended Link Service Send Reply */
+typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY
+{
+    U8                      Reserved;           /* 00h */
+    U8                      AliasIndex;         /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_EXLINK_SERVICE_SEND_REPLY, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REPLY,
+  ExLinkServiceSendReply_t, MPI_POINTER pExLinkServiceSendReply_t;
+
+/****************************************************************************/
+/* FC Abort messages                                                        */
+/****************************************************************************/
+
+typedef struct _MSG_FC_ABORT_REQUEST
+{
+    U8                      AbortFlags;                 /* 00h */
+    U8                      AbortType;                  /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     TransactionContextToAbort;  /* 0Ch */
+} MSG_FC_ABORT_REQUEST, MPI_POINTER PTR_MSG_FC_ABORT_REQUEST,
+  FcAbortRequest_t, MPI_POINTER pFcAbortRequest_t;
+
+#define FC_ABORT_FLAG_PORT_MASK                 (0x01)
+
+#define FC_ABORT_TYPE_ALL_FC_BUFFERS            (0x00)
+#define FC_ABORT_TYPE_EXACT_FC_BUFFER           (0x01)
+#define FC_ABORT_TYPE_CT_SEND_REQUEST           (0x02)
+#define FC_ABORT_TYPE_EXLINKSEND_REQUEST        (0x03)
+
+/* FC Abort Reply */
+typedef struct _MSG_FC_ABORT_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_FC_ABORT_REPLY, MPI_POINTER PTR_MSG_FC_ABORT_REPLY,
+  FcAbortReply_t, MPI_POINTER pFcAbortReply_t;
+
+
+/****************************************************************************/
+/* FC Common Transport Send messages                                        */
+/****************************************************************************/
+
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      AliasIndex;         /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U32                     MsgFlags_Did;       /* 04h */
+    U32                     MsgContext;         /* 08h */
+    U16                     CTCommandCode;      /* 0Ch */
+    U8                      FsType;             /* 0Eh */
+    U8                      Reserved1;          /* 0Fh */
+    SGE_SIMPLE_UNION        SGL;                /* 10h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+ MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REQUEST,
+  FcCommonTransportSendRequest_t, MPI_POINTER pFcCommonTransportSendRequest_t;
+
+#define MPI_FC_CT_SEND_DID_MASK                 (0x00FFFFFF)
+#define MPI_FC_CT_SEND_DID_SHIFT                (0)
+#define MPI_FC_CT_SEND_MSGFLAGS_MASK            (0xFF000000)
+#define MPI_FC_CT_SEND_MSGFLAGS_SHIFT           (24)
+
+
+/* FC Common Transport Send Reply */
+typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY
+{
+    U8                      Reserved;           /* 00h */
+    U8                      AliasIndex;         /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     ResponseLength;     /* 14h */
+} MSG_FC_COMMON_TRANSPORT_SEND_REPLY, MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REPLY,
+  FcCommonTransportSendReply_t, MPI_POINTER pFcCommonTransportSendReply_t;
+
+
+/****************************************************************************/
+/* FC Primitive Send messages                                               */
+/****************************************************************************/
+
+typedef struct _MSG_FC_PRIMITIVE_SEND_REQUEST
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      FcPrimitive[4];     /* 0Ch */
+} MSG_FC_PRIMITIVE_SEND_REQUEST, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REQUEST,
+  FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t;
+
+#define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK       (0x01)
+#define MPI_FC_PRIM_SEND_FLAGS_RESET_LINK      (0x04)
+#define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND       (0x08)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE       (0x10)
+#define MPI_FC_PRIM_SEND_FLAGS_SEND_AROUND     (0x20)
+#define MPI_FC_PRIM_SEND_FLAGS_UNTIL_FULL      (0x40)
+#define MPI_FC_PRIM_SEND_FLAGS_FOREVER         (0x80)
+
+/* FC Primitive Send Reply */
+typedef struct _MSG_FC_PRIMITIVE_SEND_REPLY
+{
+    U8                      SendFlags;          /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved1;          /* 04h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_FC_PRIMITIVE_SEND_REPLY, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REPLY,
+  FcPrimitiveSendReply_t, MPI_POINTER pFcPrimitiveSendReply_t;
+
+#endif
+
diff --git a/xen/drivers/message/fusion/lsi/mpi_history.txt b/xen/drivers/message/fusion/lsi/mpi_history.txt
new file mode 100644 (file)
index 0000000..0deb772
--- /dev/null
@@ -0,0 +1,276 @@
+
+ ==============================
+ MPI Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2001 LSI Logic Corporation.
+
+ ---------------------------------------
+ Header Set Release Version:    01.01.10
+ Header Set Release Date:       04-09-01
+ ---------------------------------------
+
+ Filename               Current version     Prior version
+ ----------             ---------------     -------------
+ mpi.h                  01.01.07            01.01.06
+ mpi_ioc.h              01.01.07            01.01.06
+ mpi_cnfg.h             01.01.11            01.01.10
+ mpi_init.h             01.01.05            01.01.04
+ mpi_targ.h             01.01.04            01.01.04
+ mpi_fc.h               01.01.07            01.01.06
+ mpi_lan.h              01.01.03            01.01.03
+ mpi_raid.h             01.01.02            01.01.02
+ mpi_type.h             01.01.02            01.01.02
+ mpi_history.txt        01.01.09            01.01.09
+
+
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+
+mpi.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition.
+ *  06-06-00  01.00.01  Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR.
+ *  06-22-00  01.00.02  Added MPI_IOCSTATUS_LAN_ definitions.
+ *                      Removed LAN_SUSPEND function definition.
+ *                      Added MPI_MSGFLAGS_CONTINUATION_REPLY definition.
+ *  06-30-00  01.00.03  Added MPI_CONTEXT_REPLY_TYPE_LAN definition.
+ *                      Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros.
+ *  07-27-00  01.00.04  Added MPI_FAULT_ definitions.
+ *                      Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions.
+ *                      Added MPI_IOCSTATUS_INTERNAL_ERROR definition.
+ *                      Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added new function codes.
+ *  01-09-01  01.01.03  Added more definitions to the system interface section
+ *                      Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT.
+ *  01-25-01  01.01.04  Changed MPI_VERSION_MINOR from 0x00 to 0x01.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *                      Added defines for MPI_DIAG_PREVENT_IOC_BOOT and
+ *                      MPI_DIAG_CLEAR_FLASH_BAD_SIG.
+ *                      Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines.
+ *  02-27-01  01.01.06  Removed MPI_HOST_INDEX_REGISTER define.
+ *                      Added function codes for RAID.
+ *  04-09-01  01.01.07  Added alternate define for MPI_DOORBELL_ACTIVE,
+ *                      MPI_DOORBELL_USED, to better match the spec.
+ *  --------------------------------------------------------------------------
+
+mpi_ioc.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added _MSG_IOC_INIT_REPLY structure.
+ *  06-06-00  01.00.01  Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ *  06-12-00  01.00.02  Added _MSG_PORT_ENABLE_REPLY structure.
+ *                      Added _MSG_EVENT_ACK_REPLY structure.
+ *                      Added _MSG_FW_DOWNLOAD_REPLY structure.
+ *                      Added _MSG_TOOLBOX_REPLY structure.
+ *  06-30-00  01.00.03  Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ *  07-27-00  01.00.04  Added _EVENT_DATA structure definitions for _SCSI,
+ *                      _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ *  08-11-00  01.00.05  Switched positions of MsgLength and Function fields in
+ *                      _MSG_EVENT_ACK_REPLY structure to match specification.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added a value for Manufacturer to WhoInit
+ *  12-04-00  01.01.02  Modified IOCFacts reply, added FWUpload messages, and
+ *                      removed toolbox message.
+ *  01-09-01  01.01.03  Added event enabled and disabled defines.
+ *                      Added structures for FwHeader and DataHeader.
+ *                      Added ImageType to FwUpload reply.
+ *  02-20-01  01.01.04  Started using MPI_POINTER.
+ *  02-27-01  01.01.05  Added event for RAID status change and its event data.
+ *                      Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ *  03-27-01  01.01.06  Added defines for ProductId field of MPI_FW_HEADER.
+ *                      Added structure offset comments.
+ *  04-09-01  01.01.07  Added structure EVENT_DATA_EVENT_CHANGE.
+ *  --------------------------------------------------------------------------
+
+mpi_cnfg.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added _PAGEVERSION definitions for all pages.
+ *                      Added FcPhLowestVersion, FcPhHighestVersion, Reserved2
+ *                      fields to FC_DEVICE_0 page, updated the page version.
+ *                      Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in
+ *                      SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages
+ *                      and updated the page versions.
+ *                      Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
+ *                      page and updated the page version.
+ *                      Added Information field and _INFO_PARAMS_NEGOTIATED
+ *                      definitionto SCSI_DEVICE_0 page.
+ *  06-22-00  01.00.03  Removed batch controls from LAN_0 page and updated the
+ *                      page version.
+ *                      Added BucketsRemaining to LAN_1 page, redefined the
+ *                      state values, and updated the page version.
+ *                      Revised bus width definitions in SCSI_PORT_0,
+ *                      SCSI_DEVICE_0 and SCSI_DEVICE_1 pages.
+ *  06-30-00  01.00.04  Added MaxReplySize to LAN_1 page and updated the page
+ *                      version.
+ *                      Moved FC_DEVICE_0 PageAddress description to spec.
+ *  07-27-00  01.00.05  Corrected the SubsystemVendorID and SubsystemID field
+ *                      widths in IOC_0 page and updated the page version.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Added Manufacturing pages, IO Unit Page 2, SCSI SPI
+ *                      Port Page 2, FC Port Page 4, FC Port Page 5
+ *  12-04-00  01.01.03  Config page changes to match MPI rev 1.00.01.
+ *  12-05-00  01.01.04  Modified config page actions.
+ *  01-09-01  01.01.05  Added defines for page address formats.
+ *                      Data size for Manufacturing pages 2 and 3 no longer
+ *                      defined here.
+ *                      Io Unit Page 2 size is fixed at 4 adapters and some
+ *                      flags were changed.
+ *                      SCSI Port Page 2 Device Settings modified.
+ *                      New fields added to FC Port Page 0 and some flags
+ *                      cleaned up.
+ *                      Removed impedance flash from FC Port Page 1.
+ *                      Added FC Port pages 6 and 7.
+ *  01-25-01  01.01.06  Added MaxInitiators field to FcPortPage0.
+ *  01-29-01  01.01.07  Changed some defines to make them 32 character unique.
+ *                      Added some LinkType defines for FcPortPage0.
+ *  02-20-01  01.01.08  Started using MPI_POINTER.
+ *  02-27-01  01.01.09  Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with
+ *                      MPI_CONFIG_PAGETYPE_RAID_VOLUME.
+ *                      Added definitions and structures for IOC Page 2 and
+ *                      RAID Volume Page 2.
+ *  03-27-01  01.01.10  Added CONFIG_PAGE_FC_PORT_8 and CONFIG_PAGE_FC_PORT_9.
+ *                      CONFIG_PAGE_FC_PORT_3 now supports persistent by DID.
+ *                      Added VendorId and ProductRevLevel fields to
+ *                      RAIDVOL2_IM_PHYS_ID struct.
+ *                      Modified values for MPI_FCPORTPAGE0_FLAGS_ATTACH_
+ *                      defines to make them compatible to MPI version 1.0.
+ *                      Added structure offset comments.
+ *  04-09-01  01.01.11  Added some new defines for the PageAddress field and
+ *                      removed some obsolete ones.
+ *                      Added IO Unit Page 3.
+ *                      Modified defines for Scsi Port Page 2.
+ *                      Modified RAID Volume Pages.
+ *  --------------------------------------------------------------------------
+
+mpi_init.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added MPI_SCSI_RSP_INFO_ definitions.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *  03-27-01  01.01.04  Added structure offset comments.
+ *  04-10-01  01.01.05  Added new MsgFlag for MSG_SCSI_TASK_MGMT.
+ *  --------------------------------------------------------------------------
+
+mpi_targ.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-22-00  01.00.02  Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ *                      Corrected DECSRIPTOR typo to DESCRIPTOR.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Modified target mode to use IoIndex instead of
+ *                      HostIndex and IocIndex. Added Alias.
+ *  01-09-01  01.01.02  Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ *                      and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ *                      MPI_TARGET_FCP_CMD_BUFFER.
+ *  03-27-01  01.01.04  Added structure offset comments.
+ *  --------------------------------------------------------------------------
+
+mpi_fc.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added _MSG_FC_ABORT_REPLY structure.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  12-04-00  01.01.02  Added messages for Common Transport Send and
+ *                      Primitive Send.
+ *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *                      and modified the FcPrimitiveSend flags.
+ *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
+ *                      field.
+ *                      Added FC_ABORT_TYPE_CT_SEND_REQUEST and
+ *                      FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND.
+ *  02-20-01  01.01.05  Started using MPI_POINTER.
+ *  03-27-01  01.01.06  Added Flags field to MSG_LINK_SERVICE_BUFFER_POST_REPLY
+ *                      and defined MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED.
+ *                      Added MPI_FC_PRIM_SEND_FLAGS_RESET_LINK define.
+ *                      Added structure offset comments.
+ *  04-09-01  01.01.07  Added RspLength field to MSG_LINK_SERVICE_RSP_REQUEST.
+ *  --------------------------------------------------------------------------
+
+mpi_lan.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ *                      Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ *                      Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added MPI_ to BUCKETSTATUS_ definitions.
+ *  06-22-00  01.00.03  Major changes to match new LAN definition in 1.0 spec.
+ *  06-30-00  01.00.04  Added Context Reply definitions per revised proposal.
+ *                      Changed transaction context usage to bucket/buffer.
+ *  07-05-00  01.00.05  Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ *                      to lan private header file
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Started using MPI_POINTER.
+ *  03-27-01  01.01.03  Added structure offset comments.
+ *  --------------------------------------------------------------------------
+
+mpi_raid.h
+ *  02-27-01  01.01.01  Original release for this file.
+ *  03-27-01  01.01.02  Added structure offset comments.
+ *  --------------------------------------------------------------------------
+
+mpi_type.h
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  --------------------------------------------------------------------------
+
+mpi_history.txt         Parts list history
+
+Filename    01.01.10
+----------  --------
+mpi.h       01.01.07
+mpi_ioc.h   01.01.07
+mpi_cnfg.h  01.01.11
+mpi_init.h  01.01.05
+mpi_targ.h  01.01.04
+mpi_fc.h    01.01.07
+mpi_lan.h   01.01.03
+mpi_raid.h  01.01.02
+mpi_type.h  01.01.02
+
+Filename    01.01.09   01.01.08   01.01.07   01.01.06   01.01.05   01.01.04
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.01.06   01.01.06   01.01.05   01.01.04   01.01.04   01.01.03
+mpi_ioc.h   01.01.06   01.01.05   01.01.04   01.01.03   01.01.03   01.01.03
+mpi_cnfg.h  01.01.10   01.01.09   01.01.08   01.01.07   01.01.06   01.01.05
+mpi_init.h  01.01.04   01.01.03   01.01.03   01.01.02   01.01.02   01.01.02
+mpi_targ.h  01.01.04   01.01.03   01.01.03   01.01.02   01.01.02   01.01.02
+mpi_fc.h    01.01.06   01.01.05   01.01.05   01.01.04   01.01.04   01.01.03
+mpi_lan.h   01.01.03   01.01.02   01.01.02   01.01.01   01.01.01   01.01.01
+mpi_raid.h  01.01.02   01.01.01
+mpi_type.h  01.01.02   01.01.02   01.01.02   01.01.01   01.01.01   01.01.01
+
+Filename    01.01.03   01.01.02   01.01.01   01.00.07   01.00.06   01.00.05
+----------  --------   --------   --------   --------   --------   --------
+mpi.h       01.01.02   01.01.02   01.01.01   01.00.04   01.00.04   01.00.03
+mpi_ioc.h   01.01.02   01.01.02   01.01.01   01.00.05   01.00.04   01.00.03
+mpi_cnfg.h  01.01.04   01.01.03   01.01.01   01.00.05   01.00.05   01.00.04
+mpi_init.h  01.01.02   01.01.02   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_targ.h  01.01.01   01.01.01   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_fc.h    01.01.02   01.01.02   01.01.01   01.00.02   01.00.02   01.00.02
+mpi_lan.h   01.01.01   01.01.01   01.01.01   01.00.05   01.00.05   01.00.05
+mpi_type.h  01.01.01   01.01.01   01.01.01   01.00.01   01.00.01   01.00.01
+
+Filename     01.00.04   01.00.03   01.00.02   01.00.01   00.10.02   00.10.01
+----------   --------   --------   --------   --------   --------   --------
+mpi.h        01.00.02   01.00.01   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_ioc.h    01.00.02   01.00.02   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_cnfg.h   01.00.03   01.00.02   01.00.02   01.00.01   00.10.01   00.10.01
+mpi_init.h   01.00.02   01.00.02   01.00.02   01.00.01   00.10.02   00.10.01
+mpi_targ.h   01.00.02   01.00.01   01.00.01   01.00.01   00.10.01   00.10.01
+mpi_fc.h     01.00.02   01.00.02   01.00.01   01.00.01   00.10.01   00.10.01
+mpi_lan.h    01.00.03   01.00.02   01.00.01   01.00.01   00.10.02   00.10.01
+mpi_type.h   01.00.01   01.00.01   01.00.01   01.00.01   00.10.01   00.10.01
+
+
+ *  --------------------------------------------------------------------------
+
diff --git a/xen/drivers/message/fusion/lsi/mpi_init.h b/xen/drivers/message/fusion/lsi/mpi_init.h
new file mode 100644 (file)
index 0000000..4b3256e
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_INIT.H
+ *          Title:  MPI initiator mode messages and structures
+ *  Creation Date:  June 8, 2000
+ *
+ *    MPI_INIT.H Version:  01.02.05
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added SenseBufferLength to _MSG_SCSI_IO_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-08-00  01.00.02  Added MPI_SCSI_RSP_INFO_ definitions.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *  12-04-00  01.01.02  Added MPI_SCSIIO_CONTROL_NO_DISCONNECT.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *  03-27-01  01.01.04  Added structure offset comments.
+ *  04-10-01  01.01.05  Added new MsgFlag for MSG_SCSI_TASK_MGMT.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  08-29-01  01.02.02  Added MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET.
+ *                      Added MPI_SCSI_STATE_QUEUE_TAG_REJECTED for
+ *                      MSG_SCSI_IO_REPLY.
+ *  09-28-01  01.02.03  Added structures and defines for SCSI Enclosure
+ *                      Processor messages.
+ *  10-04-01  01.02.04  Added defines for SEP request Action field.
+ *  05-31-02  01.02.05  Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define
+ *                      for SCSI IO requests.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_INIT_H
+#define MPI_INIT_H
+
+
+/*****************************************************************************
+*
+*               S C S I    I n i t i a t o r    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  SCSI IO messages and assocaited structures                              */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_REQUEST
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved;           /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      LUN[8];             /* 0Ch */
+    U32                     Control;            /* 14h */
+    U8                      CDB[16];            /* 18h */
+    U32                     DataLength;         /* 28h */
+    U32                     SenseBufferLowAddr; /* 2Ch */
+    SGE_IO_UNION            SGL;                /* 30h */
+} MSG_SCSI_IO_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_REQUEST,
+  SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t;
+
+
+/* SCSI IO MsgFlags bits */
+
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH              (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32           (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64           (0x01)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION           (0x02)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST           (0x00)
+#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC            (0x02)
+#define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR  (0x04)
+
+/* SCSI IO LUN fields */
+
+#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING   (0x0000FFFF)
+#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING  (0xFFFF0000)
+#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING   (0x0000FFFF)
+#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING  (0xFFFF0000)
+#define MPI_SCSIIO_LUN_LEVEL_1_WORD             (0xFF00)
+#define MPI_SCSIIO_LUN_LEVEL_1_DWORD            (0x0000FF00)
+
+/* SCSI IO Control bits */
+
+#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK   (0x03000000)
+#define MPI_SCSIIO_CONTROL_NODATATRANSFER       (0x00000000)
+#define MPI_SCSIIO_CONTROL_WRITE                (0x01000000)
+#define MPI_SCSIIO_CONTROL_READ                 (0x02000000)
+
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK       (0x3C000000)
+#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT      (26)
+
+#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK   (0x00000700)
+#define MPI_SCSIIO_CONTROL_SIMPLEQ              (0x00000000)
+#define MPI_SCSIIO_CONTROL_HEADOFQ              (0x00000100)
+#define MPI_SCSIIO_CONTROL_ORDEREDQ             (0x00000200)
+#define MPI_SCSIIO_CONTROL_ACAQ                 (0x00000400)
+#define MPI_SCSIIO_CONTROL_UNTAGGED             (0x00000500)
+#define MPI_SCSIIO_CONTROL_NO_DISCONNECT        (0x00000700)
+
+#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK      (0x00FF0000)
+#define MPI_SCSIIO_CONTROL_OBSOLETE             (0x00800000)
+#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV        (0x00400000)
+#define MPI_SCSIIO_CONTROL_TARGET_RESET         (0x00200000)
+#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV        (0x00100000)
+#define MPI_SCSIIO_CONTROL_RESERVED             (0x00080000)
+#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV     (0x00040000)
+#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET       (0x00020000)
+#define MPI_SCSIIO_CONTROL_RESERVED2            (0x00010000)
+
+
+/* SCSI IO reply structure */
+typedef struct _MSG_SCSI_IO_REPLY
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved;           /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      SCSIStatus;         /* 0Ch */
+    U8                      SCSIState;          /* 0Dh */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferCount;      /* 14h */
+    U32                     SenseCount;         /* 18h */
+    U32                     ResponseInfo;       /* 1Ch */
+} MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY,
+  SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
+
+
+/* SCSI IO Reply SCSIStatus values (SAM-2 status codes) */
+
+#define MPI_SCSI_STATUS_SUCCESS                 (0x00)
+#define MPI_SCSI_STATUS_CHECK_CONDITION         (0x02)
+#define MPI_SCSI_STATUS_CONDITION_MET           (0x04)
+#define MPI_SCSI_STATUS_BUSY                    (0x08)
+#define MPI_SCSI_STATUS_INTERMEDIATE            (0x10)
+#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET    (0x14)
+#define MPI_SCSI_STATUS_RESERVATION_CONFLICT    (0x18)
+#define MPI_SCSI_STATUS_COMMAND_TERMINATED      (0x22)
+#define MPI_SCSI_STATUS_TASK_SET_FULL           (0x28)
+#define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
+
+
+/* SCSI IO Reply SCSIState values */
+
+#define MPI_SCSI_STATE_AUTOSENSE_VALID          (0x01)
+#define MPI_SCSI_STATE_AUTOSENSE_FAILED         (0x02)
+#define MPI_SCSI_STATE_NO_SCSI_STATUS           (0x04)
+#define MPI_SCSI_STATE_TERMINATED               (0x08)
+#define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
+#define MPI_SCSI_STATE_QUEUE_TAG_REJECTED       (0x20)
+
+/* SCSI IO Reply ResponseInfo values */
+/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
+
+#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE     (0x00000000)
+#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR   (0x01000000)
+#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID   (0x02000000)
+#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR     (0x03000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000)
+#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED      (0x05000000)
+#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE   (0x06000000)
+
+
+/****************************************************************************/
+/*  SCSI Task Management messages                                           */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_TASK_MGMT
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Reserved;           /* 04h */
+    U8                      TaskType;           /* 05h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      LUN[8];             /* 0Ch */
+    U32                     Reserved2[7];       /* 14h */
+    U32                     TaskMsgContext;     /* 30h */
+} MSG_SCSI_TASK_MGMT, MPI_POINTER PTR_SCSI_TASK_MGMT,
+  SCSITaskMgmt_t, MPI_POINTER pSCSITaskMgmt_t;
+
+/* TaskType values */
+
+#define MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK            (0x01)
+#define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET         (0x02)
+#define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET          (0x03)
+#define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS             (0x04)
+#define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET    (0x05)
+
+/* MsgFlags bits */
+#define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION   (0x00)
+#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION      (0x02)
+#define MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION (0x04)
+
+/* SCSI Task Management Reply */
+typedef struct _MSG_SCSI_TASK_MGMT_REPLY
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Reserved;           /* 04h */
+    U8                      TaskType;           /* 05h */
+    U8                      Reserved1;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      Reserved2[2];       /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TerminationCount;   /* 14h */
+} MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY,
+  SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t;
+
+
+/****************************************************************************/
+/*  SCSI Enclosure Processor messages                                       */
+/****************************************************************************/
+
+typedef struct _MSG_SEP_REQUEST
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Action;             /* 04h */
+    U8                      Reserved1;          /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     SlotStatus;         /* 0Ch */
+} MSG_SEP_REQUEST, MPI_POINTER PTR_MSG_SEP_REQUEST,
+  SEPRequest_t, MPI_POINTER pSEPRequest_t;
+
+/* Action defines */
+#define MPI_SEP_REQ_ACTION_WRITE_STATUS                 (0x00)
+#define MPI_SEP_REQ_ACTION_READ_STATUS                  (0x01)
+
+/* SlotStatus bits for MSG_SEP_REQUEST */
+#define MPI_SEP_REQ_SLOTSTATUS_NO_ERROR                 (0x00000001)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_FAULTY               (0x00000002)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_REBUILDING           (0x00000004)
+#define MPI_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY          (0x00000008)
+#define MPI_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY        (0x00000010)
+#define MPI_SEP_REQ_SLOTSTATUS_PARITY_CHECK             (0x00000020)
+#define MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT          (0x00000040)
+#define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED             (0x00000080)
+#define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE                (0x00000100)
+#define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED          (0x00000200)
+#define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST         (0x00020000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE           (0x00040000)
+#define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT           (0x00080000)
+#define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE              (0x00400000)
+#define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS          (0x04000000)
+#define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS          (0x08000000)
+#define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF                  (0x10000000)
+#define MPI_SEP_REQ_SLOTSTATUS_SWAP_RESET               (0x80000000)
+
+
+typedef struct _MSG_SEP_REPLY
+{
+    U8                      TargetID;           /* 00h */
+    U8                      Bus;                /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Action;             /* 04h */
+    U8                      Reserved1;          /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     SlotStatus;         /* 14h */
+} MSG_SEP_REPLY, MPI_POINTER PTR_MSG_SEP_REPLY,
+  SEPReply_t, MPI_POINTER pSEPReply_t;
+
+/* SlotStatus bits for MSG_SEP_REPLY */
+#define MPI_SEP_REPLY_SLOTSTATUS_NO_ERROR               (0x00000001)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_FAULTY             (0x00000002)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING         (0x00000004)
+#define MPI_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY        (0x00000008)
+#define MPI_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY      (0x00000010)
+#define MPI_SEP_REPLY_SLOTSTATUS_PARITY_CHECK           (0x00000020)
+#define MPI_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT        (0x00000040)
+#define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED           (0x00000080)
+#define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE              (0x00000100)
+#define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED        (0x00000200)
+#define MPI_SEP_REPLY_SLOTSTATUS_REPORT                 (0x00010000)
+#define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST       (0x00020000)
+#define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY           (0x00040000)
+#define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY           (0x00080000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE          (0x00400000)
+#define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED       (0x01000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED       (0x02000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS        (0x04000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_A_ENABLE_BYPASS        (0x08000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_DEV_OFF                (0x10000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_FAULT_SENSED           (0x40000000)
+#define MPI_SEP_REPLY_SLOTSTATUS_SWAPPED                (0x80000000)
+
+#endif
diff --git a/xen/drivers/message/fusion/lsi/mpi_ioc.h b/xen/drivers/message/fusion/lsi/mpi_ioc.h
new file mode 100644 (file)
index 0000000..c58a4f4
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_IOC.H
+ *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
+ *  Creation Date:  August 11, 2000
+ *
+ *    MPI_IOC.H Version:  01.02.06
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added _MSG_IOC_INIT_REPLY structure.
+ *  06-06-00  01.00.01  Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY.
+ *  06-12-00  01.00.02  Added _MSG_PORT_ENABLE_REPLY structure.
+ *                      Added _MSG_EVENT_ACK_REPLY structure.
+ *                      Added _MSG_FW_DOWNLOAD_REPLY structure.
+ *                      Added _MSG_TOOLBOX_REPLY structure.
+ *  06-30-00  01.00.03  Added MaxLanBuckets to _PORT_FACT_REPLY structure.
+ *  07-27-00  01.00.04  Added _EVENT_DATA structure definitions for _SCSI,
+ *                      _LINK_STATUS, _LOOP_STATE and _LOGOUT.
+ *  08-11-00  01.00.05  Switched positions of MsgLength and Function fields in
+ *                      _MSG_EVENT_ACK_REPLY structure to match specification.
+ *  11-02-00  01.01.01  Original release for post 1.0 work.
+ *                      Added a value for Manufacturer to WhoInit.
+ *  12-04-00  01.01.02  Modified IOCFacts reply, added FWUpload messages, and
+ *                      removed toolbox message.
+ *  01-09-01  01.01.03  Added event enabled and disabled defines.
+ *                      Added structures for FwHeader and DataHeader.
+ *                      Added ImageType to FwUpload reply.
+ *  02-20-01  01.01.04  Started using MPI_POINTER.
+ *  02-27-01  01.01.05  Added event for RAID status change and its event data.
+ *                      Added IocNumber field to MSG_IOC_FACTS_REPLY.
+ *  03-27-01  01.01.06  Added defines for ProductId field of MPI_FW_HEADER.
+ *                      Added structure offset comments.
+ *  04-09-01  01.01.07  Added structure EVENT_DATA_EVENT_CHANGE.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *                      New format for FWVersion and ProductId in
+ *                      MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
+ *  08-31-01  01.02.02  Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ *                      related structure and defines.
+ *                      Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
+ *                      Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
+ *                      Replaced a reserved field in MSG_IOC_FACTS_REPLY with
+ *                      IOCExceptions and changed DataImageSize to reserved.
+ *                      Added MPI_FW_DOWNLOAD_ITYPE_NVSTORE_DATA and
+ *                      MPI_FW_UPLOAD_ITYPE_NVDATA.
+ *  09-28-01  01.02.03  Modified Event Data for Integrated RAID.
+ *  11-01-01  01.02.04  Added defines for MPI_EXT_IMAGE_HEADER ImageType field.
+ *  03-14-02  01.02.05  Added HeaderVersion field to MSG_IOC_FACTS_REPLY.
+ *  05-31-02  01.02.06  Added define for
+ *                      MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID.
+ *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_IOC_H
+#define MPI_IOC_H
+
+
+/*****************************************************************************
+*
+*               I O C    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  IOCInit message                                                         */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_INIT
+{
+    U8                      WhoInit;                    /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Flags;                      /* 04h */
+    U8                      MaxDevices;                 /* 05h */
+    U8                      MaxBuses;                   /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     ReplyFrameSize;             /* 0Ch */
+    U8                      Reserved1[2];               /* 0Eh */
+    U32                     HostMfaHighAddr;            /* 10h */
+    U32                     SenseBufferHighAddr;        /* 14h */
+} MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT,
+  IOCInit_t, MPI_POINTER pIOCInit_t;
+
+/* WhoInit values */
+#define MPI_WHOINIT_NO_ONE                      (0x00)
+#define MPI_WHOINIT_SYSTEM_BIOS                 (0x01)
+#define MPI_WHOINIT_ROM_BIOS                    (0x02)
+#define MPI_WHOINIT_PCI_PEER                    (0x03)
+#define MPI_WHOINIT_HOST_DRIVER                 (0x04)
+#define MPI_WHOINIT_MANUFACTURER                (0x05)
+
+/* Flags values */
+#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE      (0x01)
+
+typedef struct _MSG_IOC_INIT_REPLY
+{
+    U8                      WhoInit;                    /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Flags;                      /* 04h */
+    U8                      MaxDevices;                 /* 05h */
+    U8                      MaxBuses;                   /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY,
+  IOCInitReply_t, MPI_POINTER pIOCInitReply_t;
+
+
+
+/****************************************************************************/
+/*  IOC Facts message                                                       */
+/****************************************************************************/
+
+typedef struct _MSG_IOC_FACTS
+{
+    U8                      Reserved[2];                /* 00h */
+    U8                      ChainOffset;                /* 01h */
+    U8                      Function;                   /* 02h */
+    U8                      Reserved1[3];               /* 03h */
+    U8                      MsgFlags;                   /* 04h */
+    U32                     MsgContext;                 /* 08h */
+} MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS,
+  IOCFacts_t, MPI_POINTER pIOCFacts_t;
+
+typedef struct _MPI_FW_VERSION_STRUCT
+{
+    U8                      Dev;                        /* 00h */
+    U8                      Unit;                       /* 01h */
+    U8                      Minor;                      /* 02h */
+    U8                      Major;                      /* 03h */
+} MPI_FW_VERSION_STRUCT;
+
+typedef union _MPI_FW_VERSION
+{
+    MPI_FW_VERSION_STRUCT   Struct;
+    U32                     Word;
+} MPI_FW_VERSION;
+
+/* IOC Facts Reply */
+typedef struct _MSG_IOC_FACTS_REPLY
+{
+    U16                     MsgVersion;                 /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     HeaderVersion;              /* 04h */
+    U8                      IOCNumber;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     IOCExceptions;              /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U8                      MaxChainDepth;              /* 14h */
+    U8                      WhoInit;                    /* 15h */
+    U8                      BlockSize;                  /* 16h */
+    U8                      Flags;                      /* 17h */
+    U16                     ReplyQueueDepth;            /* 18h */
+    U16                     RequestFrameSize;           /* 1Ah */
+    U16                     Reserved_0101_FWVersion;    /* 1Ch */ /* obsolete 16-bit FWVersion */
+    U16                     ProductID;                  /* 1Eh */
+    U32                     CurrentHostMfaHighAddr;     /* 20h */
+    U16                     GlobalCredits;              /* 24h */
+    U8                      NumberOfPorts;              /* 26h */
+    U8                      EventState;                 /* 27h */
+    U32                     CurrentSenseBufferHighAddr; /* 28h */
+    U16                     CurReplyFrameSize;          /* 2Ch */
+    U8                      MaxDevices;                 /* 2Eh */
+    U8                      MaxBuses;                   /* 2Fh */
+    U32                     FWImageSize;                /* 30h */
+    U32                     Reserved4;                  /* 34h */
+    MPI_FW_VERSION          FWVersion;                  /* 38h */
+} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY,
+  IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t;
+
+#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK          (0xFF00)
+#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK          (0x00FF)
+
+#define MPI_IOCFACTS_HEADERVERSION_UNIT_MASK        (0xFF00)
+#define MPI_IOCFACTS_HEADERVERSION_DEV_MASK         (0x00FF)
+
+#define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
+#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID     (0x0002)
+
+#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
+
+#define MPI_IOCFACTS_EVENTSTATE_DISABLED            (0x00)
+#define MPI_IOCFACTS_EVENTSTATE_ENABLED             (0x01)
+
+
+
+/*****************************************************************************
+*
+*               P o r t    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Port Facts message and Reply                                            */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_FACTS
+{
+     U8                     Reserved[2];                /* 00h */
+     U8                     ChainOffset;                /* 02h */
+     U8                     Function;                   /* 03h */
+     U8                     Reserved1[2];               /* 04h */
+     U8                     PortNumber;                 /* 06h */
+     U8                     MsgFlags;                   /* 07h */
+     U32                    MsgContext;                 /* 08h */
+} MSG_PORT_FACTS, MPI_POINTER PTR_MSG_PORT_FACTS,
+  PortFacts_t, MPI_POINTER pPortFacts_t;
+
+typedef struct _MSG_PORT_FACTS_REPLY
+{
+     U16                    Reserved;                   /* 00h */
+     U8                     MsgLength;                  /* 02h */
+     U8                     Function;                   /* 03h */
+     U16                    Reserved1;                  /* 04h */
+     U8                     PortNumber;                 /* 06h */
+     U8                     MsgFlags;                   /* 07h */
+     U32                    MsgContext;                 /* 08h */
+     U16                    Reserved2;                  /* 0Ch */
+     U16                    IOCStatus;                  /* 0Eh */
+     U32                    IOCLogInfo;                 /* 10h */
+     U8                     Reserved3;                  /* 14h */
+     U8                     PortType;                   /* 15h */
+     U16                    MaxDevices;                 /* 16h */
+     U16                    PortSCSIID;                 /* 18h */
+     U16                    ProtocolFlags;              /* 1Ah */
+     U16                    MaxPostedCmdBuffers;        /* 1Ch */
+     U16                    MaxPersistentIDs;           /* 1Eh */
+     U16                    MaxLanBuckets;              /* 20h */
+     U16                    Reserved4;                  /* 22h */
+     U32                    Reserved5;                  /* 24h */
+} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY,
+  PortFactsReply_t, MPI_POINTER pPortFactsReply_t;
+
+
+/* PortTypes values */
+
+#define MPI_PORTFACTS_PORTTYPE_INACTIVE         (0x00)
+#define MPI_PORTFACTS_PORTTYPE_SCSI             (0x01)
+#define MPI_PORTFACTS_PORTTYPE_FC               (0x10)
+
+/* ProtocolFlags values */
+
+#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR       (0x01)
+#define MPI_PORTFACTS_PROTOCOL_LAN              (0x02)
+#define MPI_PORTFACTS_PROTOCOL_TARGET           (0x04)
+#define MPI_PORTFACTS_PROTOCOL_INITIATOR        (0x08)
+
+
+/****************************************************************************/
+/*  Port Enable Message                                                     */
+/****************************************************************************/
+
+typedef struct _MSG_PORT_ENABLE
+{
+    U8                      Reserved[2];                /* 00h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[2];               /* 04h */
+    U8                      PortNumber;                 /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+} MSG_PORT_ENABLE, MPI_POINTER PTR_MSG_PORT_ENABLE,
+  PortEnable_t, MPI_POINTER pPortEnable_t;
+
+typedef struct _MSG_PORT_ENABLE_REPLY
+{
+    U8                      Reserved[2];                /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[2];               /* 04h */
+    U8                      PortNumber;                 /* 05h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_PORT_ENABLE_REPLY, MPI_POINTER PTR_MSG_PORT_ENABLE_REPLY,
+  PortEnableReply_t, MPI_POINTER pPortEnableReply_t;
+
+
+/*****************************************************************************
+*
+*               E v e n t    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Event Notification messages                                             */
+/****************************************************************************/
+
+typedef struct _MSG_EVENT_NOTIFY
+{
+    U8                      Switch;                     /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+} MSG_EVENT_NOTIFY, MPI_POINTER PTR_MSG_EVENT_NOTIFY,
+  EventNotification_t, MPI_POINTER pEventNotification_t;
+
+/* Event Notification Reply */
+
+typedef struct _MSG_EVENT_NOTIFY_REPLY
+{
+     U16                    EventDataLength;            /* 00h */
+     U8                     MsgLength;                  /* 02h */
+     U8                     Function;                   /* 03h */
+     U8                     Reserved1[2];               /* 04h */
+     U8                     AckRequired;                /* 06h */
+     U8                     MsgFlags;                   /* 07h */
+     U32                    MsgContext;                 /* 08h */
+     U8                     Reserved2[2];               /* 0Ch */
+     U16                    IOCStatus;                  /* 0Eh */
+     U32                    IOCLogInfo;                 /* 10h */
+     U32                    Event;                      /* 14h */
+     U32                    EventContext;               /* 18h */
+     U32                    Data[1];                    /* 1Ch */
+} MSG_EVENT_NOTIFY_REPLY, MPI_POINTER PTR_MSG_EVENT_NOTIFY_REPLY,
+  EventNotificationReply_t, MPI_POINTER pEventNotificationReply_t;
+
+/* Event Acknowledge */
+
+typedef struct _MSG_EVENT_ACK
+{
+    U8                      Reserved[2];                /* 00h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     Event;                      /* 0Ch */
+    U32                     EventContext;               /* 10h */
+} MSG_EVENT_ACK, MPI_POINTER PTR_MSG_EVENT_ACK,
+  EventAck_t, MPI_POINTER pEventAck_t;
+
+typedef struct _MSG_EVENT_ACK_REPLY
+{
+    U8                      Reserved[2];                /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY,
+  EventAckReply_t, MPI_POINTER pEventAckReply_t;
+
+/* Switch */
+
+#define MPI_EVENT_NOTIFICATION_SWITCH_OFF   (0x00)
+#define MPI_EVENT_NOTIFICATION_SWITCH_ON    (0x01)
+
+/* Event */
+
+#define MPI_EVENT_NONE                      (0x00000000)
+#define MPI_EVENT_LOG_DATA                  (0x00000001)
+#define MPI_EVENT_STATE_CHANGE              (0x00000002)
+#define MPI_EVENT_UNIT_ATTENTION            (0x00000003)
+#define MPI_EVENT_IOC_BUS_RESET             (0x00000004)
+#define MPI_EVENT_EXT_BUS_RESET             (0x00000005)
+#define MPI_EVENT_RESCAN                    (0x00000006)
+#define MPI_EVENT_LINK_STATUS_CHANGE        (0x00000007)
+#define MPI_EVENT_LOOP_STATE_CHANGE         (0x00000008)
+#define MPI_EVENT_LOGOUT                    (0x00000009)
+#define MPI_EVENT_EVENT_CHANGE              (0x0000000A)
+#define MPI_EVENT_INTEGRATED_RAID           (0x0000000B)
+#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C)
+#define MPI_EVENT_ON_BUS_TIMER_EXPIRED      (0x0000000D)
+
+/* AckRequired field values */
+
+#define MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00)
+#define MPI_EVENT_NOTIFICATION_ACK_REQUIRED     (0x01)
+
+/* EventChange Event data */
+
+typedef struct _EVENT_DATA_EVENT_CHANGE
+{
+    U8                      EventState;                 /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U16                     Reserved1;                  /* 02h */
+} EVENT_DATA_EVENT_CHANGE, MPI_POINTER PTR_EVENT_DATA_EVENT_CHANGE,
+  EventDataEventChange_t, MPI_POINTER pEventDataEventChange_t;
+
+/* SCSI Event data for Port, Bus and Device forms */
+
+typedef struct _EVENT_DATA_SCSI
+{
+    U8                      TargetID;                   /* 00h */
+    U8                      BusPort;                    /* 01h */
+    U16                     Reserved;                   /* 02h */
+} EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI,
+  EventDataScsi_t, MPI_POINTER pEventDataScsi_t;
+
+/* SCSI Device Status Change Event data */
+
+typedef struct _EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE
+{
+    U8                      TargetID;                   /* 00h */
+    U8                      Bus;                        /* 01h */
+    U8                      ReasonCode;                 /* 02h */
+    U8                      LUN;                        /* 03h */
+    U8                      ASC;                        /* 04h */
+    U8                      ASCQ;                       /* 05h */
+    U16                     Reserved;                   /* 06h */
+} EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE,
+  MPI_POINTER PTR_EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE,
+  MpiEventDataScsiDeviceStatusChange_t,
+  MPI_POINTER pMpiEventDataScsiDeviceStatusChange_t;
+
+/* MPI SCSI Device Status Change Event data ReasonCode values */
+#define MPI_EVENT_SCSI_DEV_STAT_RC_ADDED                (0x03)
+#define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING       (0x04)
+#define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA           (0x05)
+
+/* MPI Link Status Change Event data */
+
+typedef struct _EVENT_DATA_LINK_STATUS
+{
+    U8                      State;                      /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U16                     Reserved1;                  /* 02h */
+    U8                      Reserved2;                  /* 04h */
+    U8                      Port;                       /* 05h */
+    U16                     Reserved3;                  /* 06h */
+} EVENT_DATA_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_LINK_STATUS,
+  EventDataLinkStatus_t, MPI_POINTER pEventDataLinkStatus_t;
+
+#define MPI_EVENT_LINK_STATUS_FAILURE       (0x00000000)
+#define MPI_EVENT_LINK_STATUS_ACTIVE        (0x00000001)
+
+/* MPI Loop State Change Event data */
+
+typedef struct _EVENT_DATA_LOOP_STATE
+{
+    U8                      Character4;                 /* 00h */
+    U8                      Character3;                 /* 01h */
+    U8                      Type;                       /* 02h */
+    U8                      Reserved;                   /* 03h */
+    U8                      Reserved1;                  /* 04h */
+    U8                      Port;                       /* 05h */
+    U16                     Reserved2;                  /* 06h */
+} EVENT_DATA_LOOP_STATE, MPI_POINTER PTR_EVENT_DATA_LOOP_STATE,
+  EventDataLoopState_t, MPI_POINTER pEventDataLoopState_t;
+
+#define MPI_EVENT_LOOP_STATE_CHANGE_LIP     (0x0001)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPE     (0x0002)
+#define MPI_EVENT_LOOP_STATE_CHANGE_LPB     (0x0003)
+
+/* MPI LOGOUT Event data */
+
+typedef struct _EVENT_DATA_LOGOUT
+{
+    U32                     NPortID;                    /* 00h */
+    U8                      AliasIndex;                 /* 04h */
+    U8                      Port;                       /* 05h */
+    U16                     Reserved1;                  /* 06h */
+} EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
+  EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
+
+#define MPI_EVENT_LOGOUT_ALL_ALIASES        (0xFF)
+
+
+/* MPI Integrated RAID Event data */
+
+typedef struct _EVENT_DATA_RAID
+{
+    U8                      VolumeID;                   /* 00h */
+    U8                      VolumeBus;                  /* 01h */
+    U8                      ReasonCode;                 /* 02h */
+    U8                      PhysDiskNum;                /* 03h */
+    U8                      ASC;                        /* 04h */
+    U8                      ASCQ;                       /* 05h */
+    U16                     Reserved;                   /* 06h */
+    U32                     SettingsStatus;             /* 08h */
+} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID,
+  MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t;
+
+/* MPI Integrated RAID Event data ReasonCode values */
+#define MPI_EVENT_RAID_RC_VOLUME_CREATED                (0x00)
+#define MPI_EVENT_RAID_RC_VOLUME_DELETED                (0x01)
+#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED       (0x02)
+#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED         (0x03)
+#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED       (0x04)
+#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED              (0x05)
+#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED              (0x06)
+#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED     (0x07)
+#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED       (0x08)
+#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED             (0x09)
+#define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
+#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
+
+
+/*****************************************************************************
+*
+*               F i r m w a r e    L o a d    M e s s a g e s
+*
+*****************************************************************************/
+
+/****************************************************************************/
+/*  Firmware Download message and associated structures                     */
+/****************************************************************************/
+
+typedef struct _MSG_FW_DOWNLOAD
+{
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    SGE_MPI_UNION           SGL;                        /* 0Ch */
+} MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD,
+  FWDownload_t, MPI_POINTER pFWDownload_t;
+
+#define MPI_FW_DOWNLOAD_ITYPE_RESERVED      (0x00)
+#define MPI_FW_DOWNLOAD_ITYPE_FW            (0x01)
+#define MPI_FW_DOWNLOAD_ITYPE_BIOS          (0x02)
+#define MPI_FW_DOWNLOAD_ITYPE_NVDATA        (0x03)
+
+
+typedef struct _FWDownloadTCSGE
+{
+    U8                      Reserved;                   /* 00h */
+    U8                      ContextSize;                /* 01h */
+    U8                      DetailsLength;              /* 02h */
+    U8                      Flags;                      /* 03h */
+    U32                     Reserved_0100_Checksum;     /* 04h */ /* obsolete Checksum */
+    U32                     ImageOffset;                /* 08h */
+    U32                     ImageSize;                  /* 0Ch */
+} FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE,
+  FWDownloadTCSGE_t, MPI_POINTER pFWDownloadTCSGE_t;
+
+/* Firmware Download reply */
+typedef struct _MSG_FW_DOWNLOAD_REPLY
+{
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_FW_DOWNLOAD_REPLY, MPI_POINTER PTR_MSG_FW_DOWNLOAD_REPLY,
+  FWDownloadReply_t, MPI_POINTER pFWDownloadReply_t;
+
+
+/****************************************************************************/
+/*  Firmware Upload message and associated structures                       */
+/****************************************************************************/
+
+typedef struct _MSG_FW_UPLOAD
+{
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    SGE_MPI_UNION           SGL;                        /* 0Ch */
+} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD,
+  FWUpload_t, MPI_POINTER pFWUpload_t;
+
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM      (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH        (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH      (0x02)
+#define MPI_FW_UPLOAD_ITYPE_NVDATA          (0x03)
+
+typedef struct _FWUploadTCSGE
+{
+    U8                      Reserved;                   /* 00h */
+    U8                      ContextSize;                /* 01h */
+    U8                      DetailsLength;              /* 02h */
+    U8                      Flags;                      /* 03h */
+    U32                     Reserved1;                  /* 04h */
+    U32                     ImageOffset;                /* 08h */
+    U32                     ImageSize;                  /* 0Ch */
+} FW_UPLOAD_TCSGE, MPI_POINTER PTR_FW_UPLOAD_TCSGE,
+  FWUploadTCSGE_t, MPI_POINTER pFWUploadTCSGE_t;
+
+/* Firmware Upload reply */
+typedef struct _MSG_FW_UPLOAD_REPLY
+{
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      Reserved1[3];               /* 04h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     ActualImageSize;            /* 14h */
+} MSG_FW_UPLOAD_REPLY, MPI_POINTER PTR_MSG_FW_UPLOAD_REPLY,
+  FWUploadReply_t, MPI_POINTER pFWUploadReply_t;
+
+
+typedef struct _MPI_FW_HEADER
+{
+    U32                     ArmBranchInstruction0;      /* 00h */
+    U32                     Signature0;                 /* 04h */
+    U32                     Signature1;                 /* 08h */
+    U32                     Signature2;                 /* 0Ch */
+    U32                     ArmBranchInstruction1;      /* 10h */
+    U32                     ArmBranchInstruction2;      /* 14h */
+    U32                     Reserved;                   /* 18h */
+    U32                     Checksum;                   /* 1Ch */
+    U16                     VendorId;                   /* 20h */
+    U16                     ProductId;                  /* 22h */
+    MPI_FW_VERSION          FWVersion;                  /* 24h */
+    U32                     SeqCodeVersion;             /* 28h */
+    U32                     ImageSize;                  /* 2Ch */
+    U32                     NextImageHeaderOffset;      /* 30h */
+    U32                     LoadStartAddress;           /* 34h */
+    U32                     IopResetVectorValue;        /* 38h */
+    U32                     IopResetRegAddr;            /* 3Ch */
+    U32                     VersionNameWhat;            /* 40h */
+    U8                      VersionName[32];            /* 44h */
+    U32                     VendorNameWhat;             /* 64h */
+    U8                      VendorName[32];             /* 68h */
+} MPI_FW_HEADER, MPI_POINTER PTR_MPI_FW_HEADER,
+  MpiFwHeader_t, MPI_POINTER pMpiFwHeader_t;
+
+#define MPI_FW_HEADER_WHAT_SIGNATURE        (0x29232840)
+
+/* defines for using the ProductId field */
+#define MPI_FW_HEADER_PID_TYPE_MASK             (0xF000)
+#define MPI_FW_HEADER_PID_TYPE_SCSI             (0x0000)
+#define MPI_FW_HEADER_PID_TYPE_FC               (0x1000)
+
+#define MPI_FW_HEADER_PID_PROD_MASK                     (0x0F00)
+#define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI           (0x0100)
+#define MPI_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI    (0x0200)
+#define MPI_FW_HEADER_PID_PROD_TARGET_SCSI              (0x0300)
+#define MPI_FW_HEADER_PID_PROD_IM_SCSI                  (0x0400)
+#define MPI_FW_HEADER_PID_PROD_IS_SCSI                  (0x0500)
+#define MPI_FW_HEADER_PID_PROD_CTX_SCSI                 (0x0600)
+
+#define MPI_FW_HEADER_PID_FAMILY_MASK           (0x00FF)
+#define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI    (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI    (0x0002)
+#define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI    (0x0003)
+#define MPI_FW_HEADER_PID_FAMILY_1030C0_SCSI    (0x0004)
+#define MPI_FW_HEADER_PID_FAMILY_1020A0_SCSI    (0x0005)
+#define MPI_FW_HEADER_PID_FAMILY_1020B0_SCSI    (0x0006)
+#define MPI_FW_HEADER_PID_FAMILY_1020B1_SCSI    (0x0007)
+#define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI    (0x0008)
+#define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI    (0x0009)
+#define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI    (0x000A)
+#define MPI_FW_HEADER_PID_FAMILY_909_FC         (0x0000)
+#define MPI_FW_HEADER_PID_FAMILY_919_FC         (0x0001)
+#define MPI_FW_HEADER_PID_FAMILY_919X_FC        (0x0002)
+
+typedef struct _MPI_EXT_IMAGE_HEADER
+{
+    U8                      ImageType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U16                     Reserved1;                  /* 02h */
+    U32                     Checksum;                   /* 04h */
+    U32                     ImageSize;                  /* 08h */
+    U32                     NextImageHeaderOffset;      /* 0Ch */
+    U32                     LoadStartAddress;           /* 10h */
+    U32                     Reserved2;                  /* 14h */
+} MPI_EXT_IMAGE_HEADER, MPI_POINTER PTR_MPI_EXT_IMAGE_HEADER,
+  MpiExtImageHeader_t, MPI_POINTER pMpiExtImageHeader_t;
+
+/* defines for the ImageType field */
+#define MPI_EXT_IMAGE_TYPE_UNSPECIFIED          (0x00)
+#define MPI_EXT_IMAGE_TYPE_FW                   (0x01)
+#define MPI_EXT_IMAGE_TYPE_NVDATA               (0x03)
+
+#endif
diff --git a/xen/drivers/message/fusion/lsi/mpi_lan.h b/xen/drivers/message/fusion/lsi/mpi_lan.h
new file mode 100644 (file)
index 0000000..739c5cd
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_LAN.H
+ *          Title:  MPI LAN messages and structures
+ *  Creation Date:  June 30, 2000
+ *
+ *    MPI_LAN.H Version:  01.02.01
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  05-24-00  00.10.02  Added LANStatus field to _MSG_LAN_SEND_REPLY.
+ *                      Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY.
+ *                      Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-12-00  01.00.02  Added MPI_ to BUCKETSTATUS_ definitions.
+ *  06-22-00  01.00.03  Major changes to match new LAN definition in 1.0 spec.
+ *  06-30-00  01.00.04  Added Context Reply definitions per revised proposal.
+ *                      Changed transaction context usage to bucket/buffer.
+ *  07-05-00  01.00.05  Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition
+ *                      to lan private header file
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Started using MPI_POINTER.
+ *  03-27-01  01.01.03  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_LAN_H
+#define MPI_LAN_H
+
+
+/******************************************************************************
+*
+*               L A N    M e s s a g e s
+*
+*******************************************************************************/
+
+/* LANSend messages */
+
+typedef struct _MSG_LAN_SEND_REQUEST
+{
+    U16                     Reserved;           /* 00h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    SGE_MPI_UNION           SG_List[1];         /* 0Ch */
+} MSG_LAN_SEND_REQUEST, MPI_POINTER PTR_MSG_LAN_SEND_REQUEST,
+  LANSendRequest_t, MPI_POINTER pLANSendRequest_t;
+
+
+typedef struct _MSG_LAN_SEND_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Reserved2;          /* 04h */
+    U8                      NumberOfContexts;   /* 05h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     BufferContext;      /* 14h */
+} MSG_LAN_SEND_REPLY, MPI_POINTER PTR_MSG_LAN_SEND_REPLY,
+  LANSendReply_t, MPI_POINTER pLANSendReply_t;
+
+
+/* LANReceivePost */
+
+typedef struct _MSG_LAN_RECEIVE_POST_REQUEST
+{
+    U16                     Reserved;           /* 00h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     BucketCount;        /* 0Ch */
+    SGE_MPI_UNION           SG_List[1];         /* 10h */
+} MSG_LAN_RECEIVE_POST_REQUEST, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REQUEST,
+  LANReceivePostRequest_t, MPI_POINTER pLANReceivePostRequest_t;
+
+
+typedef struct _MSG_LAN_RECEIVE_POST_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      Reserved2;          /* 04h */
+    U8                      NumberOfContexts;   /* 05h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     BucketsRemaining;   /* 14h */
+    U32                     PacketOffset;       /* 18h */
+    U32                     PacketLength;       /* 1Ch */
+    U32                     BucketContext[1];   /* 20h */
+} MSG_LAN_RECEIVE_POST_REPLY, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REPLY,
+  LANReceivePostReply_t, MPI_POINTER pLANReceivePostReply_t;
+
+
+/* LANReset */
+
+typedef struct _MSG_LAN_RESET_REQUEST
+{
+    U16                     Reserved;           /* 00h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      PortNumber;         /* 05h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+} MSG_LAN_RESET_REQUEST, MPI_POINTER PTR_MSG_LAN_RESET_REQUEST,
+  LANResetRequest_t, MPI_POINTER pLANResetRequest_t;
+
+
+typedef struct _MSG_LAN_RESET_REPLY
+{
+    U16                     Reserved;           /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      PortNumber;         /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     Reserved3;          /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+} MSG_LAN_RESET_REPLY, MPI_POINTER PTR_MSG_LAN_RESET_REPLY,
+  LANResetReply_t, MPI_POINTER pLANResetReply_t;
+
+
+/****************************************************************************/
+/* LAN Context Reply defines and macros                                     */
+/****************************************************************************/
+
+#define LAN_REPLY_PACKET_LENGTH_MASK            (0x0000FFFF)
+#define LAN_REPLY_PACKET_LENGTH_SHIFT           (0)
+#define LAN_REPLY_BUCKET_CONTEXT_MASK           (0x07FF0000)
+#define LAN_REPLY_BUCKET_CONTEXT_SHIFT          (16)
+#define LAN_REPLY_BUFFER_CONTEXT_MASK           (0x07FFFFFF)
+#define LAN_REPLY_BUFFER_CONTEXT_SHIFT          (0)
+#define LAN_REPLY_FORM_MASK                     (0x18000000)
+#define LAN_REPLY_FORM_RECEIVE_SINGLE           (0x00)
+#define LAN_REPLY_FORM_RECEIVE_MULTIPLE         (0x01)
+#define LAN_REPLY_FORM_SEND_SINGLE              (0x02)
+#define LAN_REPLY_FORM_MESSAGE_CONTEXT          (0x03)
+#define LAN_REPLY_FORM_SHIFT                    (27)
+
+#define GET_LAN_PACKET_LENGTH(x)    (((x) & LAN_REPLY_PACKET_LENGTH_MASK)   \
+                                        >> LAN_REPLY_PACKET_LENGTH_SHIFT)
+
+#define SET_LAN_PACKET_LENGTH(x, lth)                                       \
+            ((x) = ((x) & ~LAN_REPLY_PACKET_LENGTH_MASK) |                  \
+                            (((lth) << LAN_REPLY_PACKET_LENGTH_SHIFT) &     \
+                                        LAN_REPLY_PACKET_LENGTH_MASK))
+
+#define GET_LAN_BUCKET_CONTEXT(x)   (((x) & LAN_REPLY_BUCKET_CONTEXT_MASK)  \
+                                        >> LAN_REPLY_BUCKET_CONTEXT_SHIFT)
+
+#define SET_LAN_BUCKET_CONTEXT(x, ctx)                                      \
+            ((x) = ((x) & ~LAN_REPLY_BUCKET_CONTEXT_MASK) |                 \
+                            (((ctx) << LAN_REPLY_BUCKET_CONTEXT_SHIFT) &    \
+                                        LAN_REPLY_BUCKET_CONTEXT_MASK))
+
+#define GET_LAN_BUFFER_CONTEXT(x)   (((x) & LAN_REPLY_BUFFER_CONTEXT_MASK)  \
+                                        >> LAN_REPLY_BUFFER_CONTEXT_SHIFT)
+
+#define SET_LAN_BUFFER_CONTEXT(x, ctx)                                      \
+            ((x) = ((x) & ~LAN_REPLY_BUFFER_CONTEXT_MASK) |                 \
+                            (((ctx) << LAN_REPLY_BUFFER_CONTEXT_SHIFT) &    \
+                                        LAN_REPLY_BUFFER_CONTEXT_MASK))
+
+#define GET_LAN_FORM(x)             (((x) & LAN_REPLY_FORM_MASK)            \
+                                        >> LAN_REPLY_FORM_SHIFT)
+
+#define SET_LAN_FORM(x, frm)                                                \
+            ((x) = ((x) & ~LAN_REPLY_FORM_MASK) |                           \
+                            (((frm) << LAN_REPLY_FORM_SHIFT) &              \
+                                        LAN_REPLY_FORM_MASK))
+
+
+/****************************************************************************/
+/* LAN Current Device State defines                                         */
+/****************************************************************************/
+
+#define MPI_LAN_DEVICE_STATE_RESET                     (0x00)
+#define MPI_LAN_DEVICE_STATE_OPERATIONAL               (0x01)
+
+
+/****************************************************************************/
+/* LAN Loopback defines                                                     */
+/****************************************************************************/
+
+#define MPI_LAN_TX_MODES_ENABLE_LOOPBACK_SUPPRESSION   (0x01)
+
+#endif
+
diff --git a/xen/drivers/message/fusion/lsi/mpi_raid.h b/xen/drivers/message/fusion/lsi/mpi_raid.h
new file mode 100644 (file)
index 0000000..c120cfa
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *  Copyright (c) 2001-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_RAID.H
+ *          Title:  MPI RAID message and structures
+ *  Creation Date:  February 27, 2001
+ *
+ *    MPI_RAID.H Version:  01.02.07
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  02-27-01  01.01.01  Original release for this file.
+ *  03-27-01  01.01.02  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Major rework for MPI v1.2 Integrated RAID changes.
+ *  10-04-01  01.02.03  Added ActionData defines for
+ *                      MPI_RAID_ACTION_DELETE_VOLUME action.
+ *  11-01-01  01.02.04  Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC.
+ *  03-14-02  01.02.05  Added define for MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT.
+ *  05-07-02  01.02.06  Added define for MPI_RAID_ACTION_ACTIVATE_VOLUME,
+ *                      MPI_RAID_ACTION_INACTIVATE_VOLUME, and
+ *                      MPI_RAID_ACTION_ADATA_INACTIVATE_ALL.
+ *  07-12-02  01.02.07  Added structures for Mailbox request and reply.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_RAID_H
+#define MPI_RAID_H
+
+
+/******************************************************************************
+*
+*        R A I D    M e s s a g e s
+*
+*******************************************************************************/
+
+
+/****************************************************************************/
+/* RAID Volume Request                                                      */
+/****************************************************************************/
+
+typedef struct _MSG_RAID_ACTION
+{
+    U8                      Action;             /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      VolumeID;           /* 04h */
+    U8                      VolumeBus;          /* 05h */
+    U8                      PhysDiskNum;        /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U32                     Reserved2;          /* 0Ch */
+    U32                     ActionDataWord;     /* 10h */
+    SGE_SIMPLE_UNION        ActionDataSGE;      /* 14h */
+} MSG_RAID_ACTION_REQUEST, MPI_POINTER PTR_MSG_RAID_ACTION_REQUEST,
+  MpiRaidActionRequest_t , MPI_POINTER pMpiRaidActionRequest_t;
+
+
+/* RAID Action request Action values */
+
+#define MPI_RAID_ACTION_STATUS                      (0x00)
+#define MPI_RAID_ACTION_INDICATOR_STRUCT            (0x01)
+#define MPI_RAID_ACTION_CREATE_VOLUME               (0x02)
+#define MPI_RAID_ACTION_DELETE_VOLUME               (0x03)
+#define MPI_RAID_ACTION_DISABLE_VOLUME              (0x04)
+#define MPI_RAID_ACTION_ENABLE_VOLUME               (0x05)
+#define MPI_RAID_ACTION_QUIESCE_PHYS_IO             (0x06)
+#define MPI_RAID_ACTION_ENABLE_PHYS_IO              (0x07)
+#define MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS      (0x08)
+#define MPI_RAID_ACTION_PHYSDISK_OFFLINE            (0x0A)
+#define MPI_RAID_ACTION_PHYSDISK_ONLINE             (0x0B)
+#define MPI_RAID_ACTION_CHANGE_PHYSDISK_SETTINGS    (0x0C)
+#define MPI_RAID_ACTION_CREATE_PHYSDISK             (0x0D)
+#define MPI_RAID_ACTION_DELETE_PHYSDISK             (0x0E)
+#define MPI_RAID_ACTION_FAIL_PHYSDISK               (0x0F)
+#define MPI_RAID_ACTION_REPLACE_PHYSDISK            (0x10)
+#define MPI_RAID_ACTION_ACTIVATE_VOLUME             (0x11)
+#define MPI_RAID_ACTION_INACTIVATE_VOLUME           (0x12)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC           (0x00000001)
+#define MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT        (0x00000002)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DELETE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
+#define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
+
+/* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
+
+
+/* RAID Action reply message */
+
+typedef struct _MSG_RAID_ACTION_REPLY
+{
+    U8                      Action;             /* 00h */
+    U8                      Reserved;           /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      VolumeID;           /* 04h */
+    U8                      VolumeBus;          /* 05h */
+    U8                      PhysDiskNum;        /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     ActionStatus;       /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     VolumeStatus;       /* 14h */
+    U32                     ActionData;         /* 18h */
+} MSG_RAID_ACTION_REPLY, MPI_POINTER PTR_MSG_RAID_ACTION_REPLY,
+  MpiRaidActionReply_t, MPI_POINTER pMpiRaidActionReply_t;
+
+
+/* RAID Volume reply ActionStatus values */
+
+#define MPI_RAID_ACTION_ASTATUS_SUCCESS             (0x0000)
+#define MPI_RAID_ACTION_ASTATUS_INVALID_ACTION      (0x0001)
+#define MPI_RAID_ACTION_ASTATUS_FAILURE             (0x0002)
+#define MPI_RAID_ACTION_ASTATUS_IN_PROGRESS         (0x0003)
+
+
+/* RAID Volume reply RAID Volume Indicator structure */
+
+typedef struct _MPI_RAID_VOL_INDICATOR
+{
+    U64                     TotalBlocks;        /* 00h */
+    U64                     BlocksRemaining;    /* 08h */
+} MPI_RAID_VOL_INDICATOR, MPI_POINTER PTR_MPI_RAID_VOL_INDICATOR,
+  MpiRaidVolIndicator_t, MPI_POINTER pMpiRaidVolIndicator_t;
+
+
+/****************************************************************************/
+/* SCSI IO RAID Passthrough Request                                         */
+/****************************************************************************/
+
+typedef struct _MSG_SCSI_IO_RAID_PT_REQUEST
+{
+    U8                      PhysDiskNum;        /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      ChainOffset;        /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      LUN[8];             /* 0Ch */
+    U32                     Control;            /* 14h */
+    U8                      CDB[16];            /* 18h */
+    U32                     DataLength;         /* 28h */
+    U32                     SenseBufferLowAddr; /* 2Ch */
+    SGE_IO_UNION            SGL;                /* 30h */
+} MSG_SCSI_IO_RAID_PT_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REQUEST,
+  SCSIIORaidPassthroughRequest_t, MPI_POINTER pSCSIIORaidPassthroughRequest_t;
+
+
+/* SCSI IO RAID Passthrough reply structure */
+
+typedef struct _MSG_SCSI_IO_RAID_PT_REPLY
+{
+    U8                      PhysDiskNum;        /* 00h */
+    U8                      Reserved1;          /* 01h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U8                      CDBLength;          /* 04h */
+    U8                      SenseBufferLength;  /* 05h */
+    U8                      Reserved2;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U8                      SCSIStatus;         /* 0Ch */
+    U8                      SCSIState;          /* 0Dh */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     TransferCount;      /* 14h */
+    U32                     SenseCount;         /* 18h */
+    U32                     ResponseInfo;       /* 1Ch */
+} MSG_SCSI_IO_RAID_PT_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_RAID_PT_REPLY,
+  SCSIIORaidPassthroughReply_t, MPI_POINTER pSCSIIORaidPassthroughReply_t;
+
+
+/****************************************************************************/
+/* Mailbox reqeust structure */
+/****************************************************************************/
+
+typedef struct _MSG_MAILBOX_REQUEST
+{
+    U16                     Reserved1;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      Reserved3;
+    U8                      MsgFlags;
+    U8                      Command[10];
+    U16                     Reserved4;
+    SGE_IO_UNION            SGL;
+} MSG_MAILBOX_REQUEST, MPI_POINTER PTR_MSG_MAILBOX_REQUEST,
+  MailboxRequest_t, MPI_POINTER pMailboxRequest_t;
+
+
+/* Mailbox reply structure */
+typedef struct _MSG_MAILBOX_REPLY
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     MailboxStatus;      /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     Reserved4;          /* 14h */
+} MSG_MAILBOX_REPLY, MPI_POINTER PTR_MSG_MAILBOX_REPLY,
+  MailboxReply_t, MPI_POINTER pMailboxReply_t;
+
+#endif
+
+
+
diff --git a/xen/drivers/message/fusion/lsi/mpi_targ.h b/xen/drivers/message/fusion/lsi/mpi_targ.h
new file mode 100644 (file)
index 0000000..adc9b36
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TARG.H
+ *          Title:  MPI Target mode messages and structures
+ *  Creation Date:  June 22, 2000
+ *
+ *    MPI_TARG.H Version:  01.02.07
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  06-22-00  01.00.02  Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure.
+ *                      Corrected DECSRIPTOR typo to DESCRIPTOR.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *                      Modified target mode to use IoIndex instead of
+ *                      HostIndex and IocIndex. Added Alias.
+ *  01-09-01  01.01.02  Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER
+ *                      and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER.
+ *  02-20-01  01.01.03  Started using MPI_POINTER.
+ *                      Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and
+ *                      MPI_TARGET_FCP_CMD_BUFFER.
+ *  03-27-01  01.01.04  Added structure offset comments.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  09-28-01  01.02.02  Added structure for MPI_TARGET_SCSI_SPI_STATUS_IU.
+ *                      Added PriorityReason field to some replies and
+ *                      defined more PriorityReason codes.
+ *                      Added some defines for to support previous version
+ *                      of MPI.
+ *  10-04-01  01.02.03  Added PriorityReason to MSG_TARGET_ERROR_REPLY.
+ *  11-01-01  01.02.04  Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY.
+ *  03-14-02  01.02.05  Modified MPI_TARGET_FCP_RSP_BUFFER to get the proper
+ *                      byte ordering.
+ *  05-31-02  01.02.06  Modified TARGET_MODE_REPLY_ALIAS_MASK to only include
+ *                      one bit.
+ *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  09-16-02  01.02.07  Added flags for confirmed completion.
+ *                      Added PRIORITY_REASON_TARGET_BUSY.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TARG_H
+#define MPI_TARG_H
+
+
+/******************************************************************************
+*
+*        S C S I    T a r g e t    M e s s a g e s
+*
+*******************************************************************************/
+
+typedef struct _CMD_BUFFER_DESCRIPTOR
+{
+    U16                     IoIndex;                    /* 00h */
+    U16                     Reserved;                   /* 02h */
+    union                                               /* 04h */
+    {
+        U32                 PhysicalAddress32;
+        U64                 PhysicalAddress64;
+    } u;
+} CMD_BUFFER_DESCRIPTOR, MPI_POINTER PTR_CMD_BUFFER_DESCRIPTOR,
+  CmdBufferDescriptor_t, MPI_POINTER pCmdBufferDescriptor_t;
+
+
+/****************************************************************************/
+/* Target Command Buffer Post Request                                       */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST
+{
+    U8                      BufferPostFlags;            /* 00h */
+    U8                      BufferCount;                /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      BufferLength;               /* 04h */
+    U8                      Reserved;                   /* 05h */
+    U8                      Reserved1;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    CMD_BUFFER_DESCRIPTOR   Buffer[1];                  /* 0Ch */
+} MSG_TARGET_CMD_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST,
+  TargetCmdBufferPostRequest_t, MPI_POINTER pTargetCmdBufferPostRequest_t;
+
+#define CMD_BUFFER_POST_FLAGS_PORT_MASK         (0x01)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_MASK    (0x80)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_32      (0)
+#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_64      (1)
+#define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR       (0x80)
+
+#define CMD_BUFFER_POST_IO_INDEX_MASK           (0x00003FFF)
+#define CMD_BUFFER_POST_IO_INDEX_MASK_0100      (0x000003FF) /* obsolete */
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY
+{
+    U8                      BufferPostFlags;            /* 00h */
+    U8                      BufferCount;                /* 01h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U8                      BufferLength;               /* 04h */
+    U8                      Reserved;                   /* 05h */
+    U8                      Reserved1;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved2;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+} MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY,
+  TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t;
+
+/* the following structure is obsolete as of MPI v1.2 */
+typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY
+{
+    U16                     Reserved;                   /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     ReplyWord;                  /* 14h */
+} MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY,
+  PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t;
+
+#define PRIORITY_REASON_NO_DISCONNECT           (0x00)
+#define PRIORITY_REASON_SCSI_TASK_MANAGEMENT    (0x01)
+#define PRIORITY_REASON_CMD_PARITY_ERR          (0x02)
+#define PRIORITY_REASON_MSG_OUT_PARITY_ERR      (0x03)
+#define PRIORITY_REASON_LQ_CRC_ERR              (0x04)
+#define PRIORITY_REASON_CMD_CRC_ERR             (0x05)
+#define PRIORITY_REASON_PROTOCOL_ERR            (0x06)
+#define PRIORITY_REASON_DATA_OUT_PARITY_ERR     (0x07)
+#define PRIORITY_REASON_DATA_OUT_CRC_ERR        (0x08)
+#define PRIORITY_REASON_TARGET_BUSY             (0x09)
+#define PRIORITY_REASON_UNKNOWN                 (0xFF)
+
+
+typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY
+{
+    U16                     Reserved;                   /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     ReplyWord;                  /* 14h */
+} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY,
+  TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t;
+
+
+typedef struct _MPI_TARGET_FCP_CMD_BUFFER
+{
+    U8      FcpLun[8];                                  /* 00h */
+    U8      FcpCntl[4];                                 /* 08h */
+    U8      FcpCdb[16];                                 /* 0Ch */
+    U32     FcpDl;                                      /* 1Ch */
+    U8      AliasIndex;                                 /* 20h */
+    U8      Reserved1;                                  /* 21h */
+    U16     Reserved2;                                  /* 22h */
+} MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
+  MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
+
+
+typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER
+{
+    /* SPI L_Q information unit */
+    U8      L_QType;                                    /* 00h */
+    U8      Reserved;                                   /* 01h */
+    U16     Tag;                                        /* 02h */
+    U8      LogicalUnitNumber[8];                       /* 04h */
+    U32     DataLength;                                 /* 0Ch */
+    /* SPI command information unit */
+    U8      ReservedFirstByteOfCommandIU;               /* 10h */
+    U8      TaskAttribute;                              /* 11h */
+    U8      TaskManagementFlags;                        /* 12h */
+    U8      AdditionalCDBLength;                        /* 13h */
+    U8      CDB[16];                                    /* 14h */
+} MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+  MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER,
+  MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer;
+
+
+/****************************************************************************/
+/* Target Assist Request                                                    */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_ASSIST_REQUEST
+{
+    U8                      StatusCode;                 /* 00h */
+    U8                      TargetAssistFlags;          /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     QueueTag;                   /* 04h */
+    U8                      Reserved;                   /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     ReplyWord;                  /* 0Ch */
+    U8                      LUN[8];                     /* 10h */
+    U32                     RelativeOffset;             /* 18h */
+    U32                     DataLength;                 /* 1Ch */
+    SGE_IO_UNION            SGL[1];                     /* 20h */
+} MSG_TARGET_ASSIST_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_REQUEST,
+  TargetAssistRequest_t, MPI_POINTER pTargetAssistRequest_t;
+
+#define TARGET_ASSIST_FLAGS_DATA_DIRECTION          (0x01)
+#define TARGET_ASSIST_FLAGS_AUTO_STATUS             (0x02)
+#define TARGET_ASSIST_FLAGS_HIGH_PRIORITY           (0x04)
+#define TARGET_ASSIST_FLAGS_CONFIRMED               (0x08)
+#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER       (0x80)
+
+
+typedef struct _MSG_TARGET_ERROR_REPLY
+{
+    U16                     Reserved;                   /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U8                      PriorityReason;             /* 0Ch */
+    U8                      Reserved3;                  /* 0Dh */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     ReplyWord;                  /* 14h */
+    U32                     TransferCount;              /* 18h */
+} MSG_TARGET_ERROR_REPLY, MPI_POINTER PTR_MSG_TARGET_ERROR_REPLY,
+  TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t;
+
+
+/****************************************************************************/
+/* Target Status Send Request                                               */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_STATUS_SEND_REQUEST
+{
+    U8                      StatusCode;                 /* 00h */
+    U8                      StatusFlags;                /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     QueueTag;                   /* 04h */
+    U8                      Reserved;                   /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     ReplyWord;                  /* 0Ch */
+    U8                      LUN[8];                     /* 10h */
+    SGE_SIMPLE_UNION        StatusDataSGE;              /* 18h */
+} MSG_TARGET_STATUS_SEND_REQUEST, MPI_POINTER PTR_MSG_TARGET_STATUS_SEND_REQUEST,
+  TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t;
+
+#define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
+#define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY      (0x04)
+#define TARGET_STATUS_SEND_FLAGS_CONFIRMED          (0x08)
+#define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
+
+/*
+ * NOTE: FCP_RSP data is big-endian. When used on a little-endian system, this
+ * structure properly orders the bytes.
+ */
+typedef struct _MPI_TARGET_FCP_RSP_BUFFER
+{
+    U8      Reserved0[8];                               /* 00h */
+    U8      Reserved1[2];                               /* 08h */
+    U8      FcpFlags;                                   /* 0Ah */
+    U8      FcpStatus;                                  /* 0Bh */
+    U32     FcpResid;                                   /* 0Ch */
+    U32     FcpSenseLength;                             /* 10h */
+    U32     FcpResponseLength;                          /* 14h */
+    U8      FcpResponseData[8];                         /* 18h */
+    U8      FcpSenseData[32]; /* Pad to 64 bytes */     /* 20h */
+} MPI_TARGET_FCP_RSP_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_RSP_BUFFER,
+  MpiTargetFcpRspBuffer, MPI_POINTER pMpiTargetFcpRspBuffer;
+
+/*
+ * NOTE: The SPI status IU is big-endian. When used on a little-endian system,
+ * this structure properly orders the bytes.
+ */
+typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU
+{
+    U8      Reserved0;                                  /* 00h */
+    U8      Reserved1;                                  /* 01h */
+    U8      Valid;                                      /* 02h */
+    U8      Status;                                     /* 03h */
+    U32     SenseDataListLength;                        /* 04h */
+    U32     PktFailuresListLength;                      /* 08h */
+    U8      SenseData[52]; /* Pad the IU to 64 bytes */ /* 0Ch */
+} MPI_TARGET_SCSI_SPI_STATUS_IU, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_STATUS_IU,
+  TargetScsiSpiStatusIU_t, MPI_POINTER pTargetScsiSpiStatusIU_t;
+
+/****************************************************************************/
+/* Target Mode Abort Request                                                */
+/****************************************************************************/
+
+typedef struct _MSG_TARGET_MODE_ABORT_REQUEST
+{
+    U8                      AbortType;                  /* 00h */
+    U8                      Reserved;                   /* 01h */
+    U8                      ChainOffset;                /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U32                     ReplyWord;                  /* 0Ch */
+    U32                     MsgContextToAbort;          /* 10h */
+} MSG_TARGET_MODE_ABORT, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT,
+  TargetModeAbort_t, MPI_POINTER pTargetModeAbort_t;
+
+#define TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS      (0x00)
+#define TARGET_MODE_ABORT_TYPE_ALL_IO               (0x01)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO             (0x02)
+#define TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST     (0x03)
+
+/* Target Mode Abort Reply */
+
+typedef struct _MSG_TARGET_MODE_ABORT_REPLY
+{
+    U16                     Reserved;                   /* 00h */
+    U8                      MsgLength;                  /* 02h */
+    U8                      Function;                   /* 03h */
+    U16                     Reserved1;                  /* 04h */
+    U8                      Reserved2;                  /* 06h */
+    U8                      MsgFlags;                   /* 07h */
+    U32                     MsgContext;                 /* 08h */
+    U16                     Reserved3;                  /* 0Ch */
+    U16                     IOCStatus;                  /* 0Eh */
+    U32                     IOCLogInfo;                 /* 10h */
+    U32                     AbortCount;                 /* 14h */
+} MSG_TARGET_MODE_ABORT_REPLY, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT_REPLY,
+  TargetModeAbortReply_t, MPI_POINTER pTargetModeAbortReply_t;
+
+
+/****************************************************************************/
+/* Target Mode Context Reply                                                */
+/****************************************************************************/
+
+#define TARGET_MODE_REPLY_IO_INDEX_MASK         (0x00003FFF)
+#define TARGET_MODE_REPLY_IO_INDEX_SHIFT        (0)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK  (0x03FFC000)
+#define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14)
+#define TARGET_MODE_REPLY_ALIAS_MASK            (0x04000000)
+#define TARGET_MODE_REPLY_ALIAS_SHIFT           (26)
+#define TARGET_MODE_REPLY_PORT_MASK             (0x10000000)
+#define TARGET_MODE_REPLY_PORT_SHIFT            (28)
+
+
+#define GET_IO_INDEX(x)     (((x) & TARGET_MODE_REPLY_IO_INDEX_MASK)           \
+                                    >> TARGET_MODE_REPLY_IO_INDEX_SHIFT)
+
+#define SET_IO_INDEX(t, i)                                                     \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_IO_INDEX_MASK) |                  \
+                              (((i) << TARGET_MODE_REPLY_IO_INDEX_SHIFT) &     \
+                                             TARGET_MODE_REPLY_IO_INDEX_MASK))
+
+#define GET_INITIATOR_INDEX(x) (((x) & TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) \
+                                   >> TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT)
+
+#define SET_INITIATOR_INDEX(t, ii)                                             \
+        ((t) = ((t) & ~TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) |               \
+                        (((ii) << TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) &   \
+                                      TARGET_MODE_REPLY_INITIATOR_INDEX_MASK))
+
+#define GET_ALIAS(x) (((x) & TARGET_MODE_REPLY_ALIAS_MASK)                     \
+                                               >> TARGET_MODE_REPLY_ALIAS_SHIFT)
+
+#define SET_ALIAS(t, a)  ((t) = ((t) & ~TARGET_MODE_REPLY_ALIAS_MASK) |        \
+                                    (((a) << TARGET_MODE_REPLY_ALIAS_SHIFT) &  \
+                                                 TARGET_MODE_REPLY_ALIAS_MASK))
+
+#define GET_PORT(x) (((x) & TARGET_MODE_REPLY_PORT_MASK)                       \
+                                               >> TARGET_MODE_REPLY_PORT_SHIFT)
+
+#define SET_PORT(t, p)  ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) |          \
+                                    (((p) << TARGET_MODE_REPLY_PORT_SHIFT) &   \
+                                                  TARGET_MODE_REPLY_PORT_MASK))
+
+/* the following obsolete values are for MPI v1.0 support */
+#define TARGET_MODE_REPLY_0100_MASK_HOST_INDEX       (0x000003FF)
+#define TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX      (0)
+#define TARGET_MODE_REPLY_0100_MASK_IOC_INDEX        (0x001FF800)
+#define TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX       (11)
+#define TARGET_MODE_REPLY_0100_PORT_MASK             (0x00400000)
+#define TARGET_MODE_REPLY_0100_PORT_SHIFT            (22)
+#define TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX  (0x1F800000)
+#define TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX (23)
+
+#define GET_HOST_INDEX_0100(x) (((x) & TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) \
+                                  >> TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX)
+
+#define SET_HOST_INDEX_0100(t, hi)                                             \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_HOST_INDEX) |           \
+                         (((hi) << TARGET_MODE_REPLY_0100_SHIFT_HOST_INDEX) &  \
+                                      TARGET_MODE_REPLY_0100_MASK_HOST_INDEX))
+
+#define GET_IOC_INDEX_0100(x)   (((x) & TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) \
+                                  >> TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX)
+
+#define SET_IOC_INDEX_0100(t, ii)                                              \
+            ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_IOC_INDEX) |            \
+                        (((ii) << TARGET_MODE_REPLY_0100_SHIFT_IOC_INDEX) &    \
+                                     TARGET_MODE_REPLY_0100_MASK_IOC_INDEX))
+
+#define GET_INITIATOR_INDEX_0100(x)                                            \
+            (((x) & TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX)               \
+                              >> TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX)
+
+#define SET_INITIATOR_INDEX_0100(t, ii)                                        \
+        ((t) = ((t) & ~TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX) |          \
+                   (((ii) << TARGET_MODE_REPLY_0100_SHIFT_INITIATOR_INDEX) &   \
+                                TARGET_MODE_REPLY_0100_MASK_INITIATOR_INDEX))
+
+
+#endif
+
diff --git a/xen/drivers/message/fusion/lsi/mpi_type.h b/xen/drivers/message/fusion/lsi/mpi_type.h
new file mode 100644 (file)
index 0000000..7e94ee9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
+ *
+ *
+ *           Name:  MPI_TYPE.H
+ *          Title:  MPI Basic type definitions
+ *  Creation Date:  June 6, 2000
+ *
+ *    MPI Version:  01.02.01
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Date      Version   Description
+ *  --------  --------  ------------------------------------------------------
+ *  05-08-00  00.10.01  Original release for 0.10 spec dated 4/26/2000.
+ *  06-06-00  01.00.01  Update version number for 1.0 release.
+ *  11-02-00  01.01.01  Original release for post 1.0 work
+ *  02-20-01  01.01.02  Added define and ifdef for MPI_POINTER.
+ *  08-08-01  01.02.01  Original release for v1.2 work.
+ *  --------------------------------------------------------------------------
+ */
+
+#ifndef MPI_TYPE_H
+#define MPI_TYPE_H
+
+
+/*******************************************************************************
+ * Define MPI_POINTER if it hasn't already been defined. By default MPI_POINTER
+ * is defined to be a near pointer. MPI_POINTER can be defined as a far pointer
+ * by defining MPI_POINTER as "far *" before this header file is included.
+ */
+#ifndef MPI_POINTER
+#define MPI_POINTER     *
+#endif
+
+
+/*****************************************************************************
+*
+*               B a s i c    T y p e s
+*
+*****************************************************************************/
+
+typedef signed   char   S8;
+typedef unsigned char   U8;
+typedef signed   short  S16;
+typedef unsigned short  U16;
+
+
+#if defined(unix) || defined(__arm) || defined(ALPHA)
+
+    typedef signed   int   S32;
+    typedef unsigned int   U32;
+
+#else
+
+    typedef signed   long  S32;
+    typedef unsigned long  U32;
+
+#endif
+
+
+typedef struct _S64
+{
+    U32          Low;
+    S32          High;
+} S64;
+
+typedef struct _U64
+{
+    U32          Low;
+    U32          High;
+} U64;
+
+
+/****************************************************************************/
+/*  Pointers                                                                */
+/****************************************************************************/
+
+typedef S8      *PS8;
+typedef U8      *PU8;
+typedef S16     *PS16;
+typedef U16     *PU16;
+typedef S32     *PS32;
+typedef U32     *PU32;
+typedef S64     *PS64;
+typedef U64     *PU64;
+
+
+#endif
+
diff --git a/xen/drivers/message/fusion/mptbase.c b/xen/drivers/message/fusion/mptbase.c
new file mode 100644 (file)
index 0000000..dcf6123
--- /dev/null
@@ -0,0 +1,6130 @@
+/*
+ *  linux/drivers/message/fusion/mptbase.c
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      This is the Fusion MPT base driver which supports multiple
+ *      (SCSI + LAN) specialized protocol drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      There are lots of people not mentioned below that deserve credit
+ *      and thanks but won't get it here - sorry in advance that you
+ *      got overlooked.
+ *
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A special thanks to Noah Romer (LSI Logic) for tons of work
+ *      and tough debugging on the LAN driver, especially early on;-)
+ *      And to Roger Hickerson (LSI Logic) for tirelessly supporting
+ *      this driver project.
+ *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
+ *      All manner of help from Stephen Shirron (LSI Logic):
+ *      low-level FC analysis, debug + various fixes in FCxx firmware,
+ *      initial port to alpha platform, various driver code optimizations,
+ *      being a faithful sounding board on all sorts of issues & ideas,
+ *      etc.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      Special thanks goes to the I2O LAN driver people at the
+ *      University of Helsinki, who, unbeknownst to them, provided
+ *      the inspiration and initial structure for this driver.
+ *
+ *      A really huge debt of gratitude is owed to Eddie C. Dost
+ *      for gobs of hard work fixing and optimizing LAN code.
+ *      THANK YOU!
+ *
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:lstephens@lsil.com)
+ *
+ *  $Id: mptbase.c,v 1.130 2003/05/07 14:08:30 pdelaney Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <xeno/config.h>
+#include <xeno/version.h>
+#include <xeno/kernel.h>
+#include <xeno/module.h>
+#include <xeno/errno.h>
+#include <xeno/init.h>
+#include <xeno/slab.h>
+#include <xeno/types.h>
+#include <xeno/pci.h>
+#include <xeno/kdev_t.h>
+#include <xeno/blkdev.h>
+#include <xeno/delay.h>
+#include <xeno/interrupt.h>            /* needed for in_interrupt() proto */
+#include <asm/byteorder.h>     /* SAE: Necessary... */
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#ifdef __sparc__
+#include <asm/irq.h>                   /* needed for __irq_itoa() proto */
+#endif
+
+#include "mptbase.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME                "Fusion MPT base driver"
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
+#define MYNAM          "mptbase"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+MODULE_LICENSE("GPL");
+
+/*
+ *  cmd line parameters
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
+MODULE_PARM(PortIo, "0-1i");
+MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
+#endif
+static int PortIo = 0;
+
+#ifdef MFCNT
+static int mfcounter = 0;
+#define PRINT_MF_COUNT 20000
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public data...
+ */
+int mpt_lan_index = -1;
+int mpt_stm_index = -1;
+
+/* SAE: Xen doesn't have proc */
+#if defined(CONFIG_PROC_FS)
+
+struct proc_dir_entry *mpt_proc_root_dir;
+
+#endif
+
+DmpServices_t *DmpService;
+
+void *mpt_v_ASCQ_TablePtr;
+const char **mpt_ScsiOpcodesPtr;
+int mpt_ASCQ_TableSz;
+
+
+#define WHOINIT_UNKNOWN                0xAA
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+                                       /* Adapter lookup table */
+       MPT_ADAPTER             *mpt_adapters[MPT_MAX_ADAPTERS];
+static MPT_ADAPTER_TRACKER      MptAdapters;
+                                       /* Callback lookup table */
+static MPT_CALLBACK             MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
+                                       /* Protocol driver class lookup table */
+static int                      MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
+                                       /* Event handler lookup table */
+static MPT_EVHANDLER            MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+                                       /* Reset handler lookup table */
+static MPT_RESETHANDLER                 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+
+static int     FusionInitCalled = 0;
+static int     mpt_base_index = -1;
+static int     last_drv_idx = -1;
+static int     isense_idx = -1;
+
+/* SAE: No wait queues or threads */
+#ifdef XENO_KILLED
+static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Forward protos...
+ */
+static void    mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
+static int     mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+
+static int     mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
+static int     mpt_adapter_install(struct pci_dev *pdev);
+static void    mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static void    mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup);
+static void    mpt_adapter_dispose(MPT_ADAPTER *ioc);
+
+static void    MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
+static int     MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
+//static u32   mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int     GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
+static int     GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int     SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
+static int     SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int     mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
+static int     mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);
+static int     mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int     KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int     SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
+static int     PrimeIocFifos(MPT_ADAPTER *ioc);
+static int     WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int     WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int     WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int     GetLanConfigPages(MPT_ADAPTER *ioc);
+static int     GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
+static int     GetIoUnitPage2(MPT_ADAPTER *ioc);
+static int     mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
+static int     mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
+static int     mpt_findImVolumes(MPT_ADAPTER *ioc);
+static void    mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
+static void    mpt_timer_expired(unsigned long data);
+static int     SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
+static int     SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
+
+#if defined(CONFIG_PROC_FS)
+static int     procmpt_create(void);
+static int     procmpt_destroy(void);
+static int     procmpt_summary_read(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data);
+static int     procmpt_version_read(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data);
+static int     procmpt_iocinfo_read(char *buf, char **start, off_t offset,
+                               int request, int *eof, void *data);
+#endif
+static void    mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
+
+//int          mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+static int     ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
+static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void    mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
+
+int            fusion_init(void);
+static void    fusion_exit(void);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  more Private data...
+ */
+#if defined(CONFIG_PROC_FS)
+struct _mpt_proc_list {
+       const char      *name;
+       int             (*f)(char *, char **, off_t, int, int *, void *);
+} mpt_proc_list[] = {
+       { "summary", procmpt_summary_read},
+       { "version", procmpt_version_read},
+};
+#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0]))
+
+struct _mpt_ioc_proc_list {
+       const char      *name;
+       int             (*f)(char *, char **, off_t, int, int *, void *);
+} mpt_ioc_proc_list[] = {
+       { "info", procmpt_iocinfo_read},
+       { "summary", procmpt_summary_read},
+};
+#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0]))
+
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 20000207 -sralston
+ *  GRRRRR...  IOSpace (port i/o) register access (for the 909) is back!
+ * 20000517 -sralston
+ *  Let's trying going back to default mmap register access...
+ */
+
+static inline u32 CHIPREG_READ32(volatile u32 *a)
+{
+       if (PortIo)
+               return inl((unsigned long)a);
+       else
+               return readl(a);
+}
+
+static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v)
+{
+       if (PortIo)
+               outl(v, (unsigned long)a);
+       else
+               writel(v, a);
+}
+
+static inline void CHIPREG_PIO_WRITE32(volatile u32 *a, u32 v)
+{
+       outl(v, (unsigned long)a);
+}
+
+static inline u32 CHIPREG_PIO_READ32(volatile u32 *a)
+{
+       return inl((unsigned long)a);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
+ *     @irq: irq number (not used)
+ *     @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ *     @r: pt_regs pointer (not used)
+ *
+ *     This routine is registered via the request_irq() kernel API call,
+ *     and handles all interrupts generated from a specific MPT adapter
+ *     (also referred to as a IO Controller or IOC).
+ *     This routine must clear the interrupt from the adapter and does
+ *     so by reading the reply FIFO.  Multiple replies may be processed
+ *     per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
+ *     which is currently set to 32 in mptbase.h.
+ *
+ *     This routine handles register-level access of the adapter but
+ *     dispatches (calls) a protocol-specific callback routine to handle
+ *     the protocol-specific details of the MPT request completion.
+ */
+static void
+mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
+{
+       MPT_ADAPTER     *ioc;
+       MPT_FRAME_HDR   *mf;
+       MPT_FRAME_HDR   *mr;
+       u32              pa;
+       int              req_idx = -1;
+       int              cb_idx;
+       int              type;
+       int              freeme;
+       int              count = 0;
+
+       ioc = bus_id;
+
+       /*
+        * Verify ioc pointer is ok
+        */
+       {
+               MPT_ADAPTER     *iocCmp;
+               iocCmp = mpt_adapter_find_first();
+               while ((ioc != iocCmp)  && iocCmp)
+                       iocCmp = mpt_adapter_find_next(iocCmp);
+
+               if (!iocCmp) {
+                       printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n");
+                       return;
+               }
+       }
+
+       /*
+        *  Drain the reply FIFO!
+        *
+        * NOTES: I've seen up to 10 replies processed in this loop, so far...
+        * Update: I've seen up to 9182 replies processed in this loop! ??
+        * Update: Limit ourselves to processing max of N replies
+        *      (bottom of loop).
+        */
+       while (1) {
+
+               if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
+                       return;
+
+               cb_idx = 0;
+               freeme = 0;
+
+               /*
+                *  Check for non-TURBO reply!
+                */
+               if (pa & MPI_ADDRESS_REPLY_A_BIT) {
+                       u32 reply_dma_low;
+                       u16 ioc_stat;
+
+                       /* non-TURBO reply!  Hmmm, something may be up...
+                        *  Newest turbo reply mechanism; get address
+                        *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
+                        */
+
+                       /* Map DMA address of reply header to cpu address.
+                        * pa is 32 bits - but the dma address may be 32 or 64 bits
+                        * get offset based only only the low addresses
+                        */
+                       reply_dma_low = (pa = (pa << 1));
+                       mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
+                                        (reply_dma_low - ioc->reply_frames_low_dma));
+
+                       req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
+                       cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
+                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+
+                       dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n",
+                                       ioc->name, mr));
+                       DBG_DUMP_REPLY_FRAME(mr)
+
+                       /* NEW!  20010301 -sralston
+                        *  Check/log IOC log info
+                        */
+                       ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
+                       if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+                               u32      log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+                               if ((int)ioc->chip_type <= (int)FC929)
+                                       mpt_fc_log_info(ioc, log_info);
+                               else
+                                       mpt_sp_log_info(ioc, log_info);
+                       }
+               } else {
+                       /*
+                        *  Process turbo (context) reply...
+                        */
+                       dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa));
+                       type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
+                       if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
+                               cb_idx = mpt_stm_index;
+                               mf = NULL;
+                               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+                       } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
+                               cb_idx = mpt_lan_index;
+                               /*
+                                * BUG FIX!  20001218 -sralston
+                                *  Blind set of mf to NULL here was fatal
+                                *  after lan_reply says "freeme"
+                                *  Fix sort of combined with an optimization here;
+                                *  added explicit check for case where lan_reply
+                                *  was just returning 1 and doing nothing else.
+                                *  For this case skip the callback, but set up
+                                *  proper mf value first here:-)
+                                */
+                               if ((pa & 0x58000000) == 0x58000000) {
+                                       req_idx = pa & 0x0000FFFF;
+                                       mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+                                       freeme = 1;
+                                       /*
+                                        *  IMPORTANT!  Invalidate the callback!
+                                        */
+                                       cb_idx = 0;
+                               } else {
+                                       mf = NULL;
+                               }
+                               mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
+                       } else {
+                               req_idx = pa & 0x0000FFFF;
+                               cb_idx = (pa & 0x00FF0000) >> 16;
+                               mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
+                               mr = NULL;
+                       }
+                       pa = 0;                                 /* No reply flush! */
+               }
+
+#ifdef MPT_DEBUG_IRQ
+               if ((int)ioc->chip_type > (int)FC929) {
+                       /* Verify mf, mr are reasonable.
+                        */
+                       if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
+                               || (mf < ioc->req_frames)) ) {
+                               printk(MYIOC_s_WARN_FMT
+                                       "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
+                               cb_idx = 0;
+                               pa = 0;
+                               freeme = 0;
+                       }
+                       if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
+                               || (mr < ioc->reply_frames)) ) {
+                               printk(MYIOC_s_WARN_FMT
+                                       "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
+                               cb_idx = 0;
+                               pa = 0;
+                               freeme = 0;
+                       }
+                       if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
+                               printk(MYIOC_s_WARN_FMT
+                                       "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
+                               cb_idx = 0;
+                               pa = 0;
+                               freeme = 0;
+                       }
+               }
+#endif
+
+               /*  Check for (valid) IO callback!  */
+               if (cb_idx) {
+                       /*  Do the callback!  */
+                       freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
+               }
+
+               if (pa) {
+                       /*  Flush (non-TURBO) reply with a WRITE!  */
+                       CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
+               }
+
+               if (freeme) {
+                       unsigned long flags;
+
+                       /*  Put Request back on FreeQ!  */
+                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                       Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+                       ioc->mfcnt--;
+#endif
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+               }
+
+               count++;
+               dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count));
+               mb();
+
+               if (count >= MPT_MAX_REPLIES_PER_ISR) {
+                       dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.",
+                                       ioc->name, count));
+                       dirqprintk((" Giving this ISR a break!\n"));
+                       return;
+               }
+
+       }       /* drain reply FIFO */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_base_reply - MPT base driver's callback routine; all base driver
+ *     "internal" request/reply processing is routed here.
+ *     Currently used for EventNotification and EventAck handling.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @reply: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *     Returns 1 indicating original alloc'd request frame ptr
+ *     should be freed, or 0 if it shouldn't.
+ */
+static int
+mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+       int freereq = 1;
+       u8 func;
+
+       dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
+                               ioc->name, (void *)mf);
+               return 1;
+       }
+
+       if (reply == NULL) {
+               dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
+                               ioc->name));
+               return 1;
+       }
+
+       if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+               dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
+               DBG_DUMP_REQUEST_FRAME_HDR(mf)
+       }
+
+       func = reply->u.hdr.Function;
+       dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
+                       ioc->name, func));
+
+       if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
+               EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
+               int evHandlers = 0;
+               int results;
+
+               results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
+               if (results != evHandlers) {
+                       /* CHECKME! Any special handling needed here? */
+                       dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
+                                       ioc->name, evHandlers, results));
+               }
+
+               /*
+                *      Hmmm...  It seems that EventNotificationReply is an exception
+                *      to the rule of one reply per request.
+                */
+               if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
+                       freereq = 0;
+
+#ifdef CONFIG_PROC_FS
+//             LogEvent(ioc, pEvReply);
+#endif
+
+       } else if (func == MPI_FUNCTION_EVENT_ACK) {
+               dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
+                               ioc->name));
+       } else if (func == MPI_FUNCTION_CONFIG) {
+               CONFIGPARMS *pCfg;
+               unsigned long flags;
+
+               dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+                               ioc->name, mf, reply));
+
+               pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
+
+               if (pCfg) {
+                       /* disable timer and remove from linked list */
+                       del_timer(&pCfg->timer);
+
+                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                       Q_DEL_ITEM(&pCfg->linkage);
+                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+                       /*
+                        *      If IOC Status is SUCCESS, save the header
+                        *      and set the status code to GOOD.
+                        */
+                       pCfg->status = MPT_CONFIG_ERROR;
+                       if (reply) {
+                               ConfigReply_t   *pReply = (ConfigReply_t *)reply;
+                               u16              status;
+
+                               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+                               dcprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+                                    status, le32_to_cpu(pReply->IOCLogInfo)));
+
+                               pCfg->status = status;
+                               if (status == MPI_IOCSTATUS_SUCCESS) {
+                                       pCfg->hdr->PageVersion = pReply->Header.PageVersion;
+                                       pCfg->hdr->PageLength = pReply->Header.PageLength;
+                                       pCfg->hdr->PageNumber = pReply->Header.PageNumber;
+                                       pCfg->hdr->PageType = pReply->Header.PageType;
+                               }
+                       }
+
+                       /*
+                        *      Wake up the original calling thread
+                        */
+                       pCfg->wait_done = 1;
+#ifdef XENO_KILLED
+                        wake_up(&mpt_waitq);
+#else
+                       mdelay(250);
+#endif
+               }
+       } else {
+               printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
+                               ioc->name, func);
+       }
+
+       /*
+        *      Conditionally tell caller to free the original
+        *      EventNotification/EventAck/unexpected request frame!
+        */
+       return freereq;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_register - Register protocol-specific main callback handler.
+ *     @cbfunc: callback function pointer
+ *     @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
+ *
+ *     This routine is called by a protocol-specific driver (SCSI host,
+ *     LAN, SCSI target) to register it's reply callback routine.  Each
+ *     protocol-specific driver must do this before it will be able to
+ *     use any IOC resources, such as obtaining request frames.
+ *
+ *     NOTES: The SCSI protocol driver currently calls this routine thrice
+ *     in order to register separate callbacks; one for "normal" SCSI IO;
+ *     one for MptScsiTaskMgmt requests; one for Scan/DV requests.
+ *
+ *     Returns a positive integer valued "handle" in the
+ *     range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
+ *     Any non-positive return value (including zero!) should be considered
+ *     an error by the caller.
+ */
+int
+mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
+{
+       int i;
+
+       last_drv_idx = -1;
+
+#ifndef MODULE
+       /*
+        *  Handle possibility of the mptscsih_detect() routine getting
+        *  called *before* fusion_init!
+        */
+       if (!FusionInitCalled) {
+               dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n"));
+               /*
+                *  NOTE! We'll get recursion here, as fusion_init()
+                *  calls mpt_register()!
+                */
+               fusion_init();
+               FusionInitCalled++;
+       }
+#endif
+
+       /*
+        *  Search for empty callback slot in this order: {N,...,7,6,5,...,1}
+        *  (slot/handle 0 is reserved!)
+        */
+       for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+               if (MptCallbacks[i] == NULL) {
+                       MptCallbacks[i] = cbfunc;
+                       MptDriverClass[i] = dclass;
+                       MptEvHandlers[i] = NULL;
+                       last_drv_idx = i;
+                       if (cbfunc != mpt_base_reply) {
+                               mpt_inc_use_count();
+                       }
+                       break;
+               }
+       }
+
+       return last_drv_idx;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_deregister - Deregister a protocol drivers resources.
+ *     @cb_idx: previously registered callback handle
+ *
+ *     Each protocol-specific driver should call this routine when it's
+ *     module is unloaded.
+ */
+void
+mpt_deregister(int cb_idx)
+{
+       if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+               MptCallbacks[cb_idx] = NULL;
+               MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+               MptEvHandlers[cb_idx] = NULL;
+
+               last_drv_idx++;
+               if (isense_idx != -1 && isense_idx <= cb_idx)
+                       isense_idx++;
+
+               if (cb_idx != mpt_base_index) {
+                       mpt_dec_use_count();
+               }
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_event_register - Register protocol-specific event callback
+ *     handler.
+ *     @cb_idx: previously registered (via mpt_register) callback handle
+ *     @ev_cbfunc: callback function
+ *
+ *     This routine can be called by one or more protocol-specific drivers
+ *     if/when they choose to be notified of MPT events.
+ *
+ *     Returns 0 for success.
+ */
+int
+mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+{
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+               return -1;
+
+       MptEvHandlers[cb_idx] = ev_cbfunc;
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_event_deregister - Deregister protocol-specific event callback
+ *     handler.
+ *     @cb_idx: previously registered callback handle
+ *
+ *     Each protocol-specific driver should call this routine
+ *     when it does not (or can no longer) handle events,
+ *     or when it's module is unloaded.
+ */
+void
+mpt_event_deregister(int cb_idx)
+{
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+               return;
+
+       MptEvHandlers[cb_idx] = NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_reset_register - Register protocol-specific IOC reset handler.
+ *     @cb_idx: previously registered (via mpt_register) callback handle
+ *     @reset_func: reset function
+ *
+ *     This routine can be called by one or more protocol-specific drivers
+ *     if/when they choose to be notified of IOC resets.
+ *
+ *     Returns 0 for success.
+ */
+int
+mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
+{
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+               return -1;
+
+       MptResetHandlers[cb_idx] = reset_func;
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
+ *     @cb_idx: previously registered callback handle
+ *
+ *     Each protocol-specific driver should call this routine
+ *     when it does not (or can no longer) handle IOC reset handling,
+ *     or when it's module is unloaded.
+ */
+void
+mpt_reset_deregister(int cb_idx)
+{
+       if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+               return;
+
+       MptResetHandlers[cb_idx] = NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
+ *     allocated per MPT adapter.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *
+ *     Returns pointer to a MPT request frame or %NULL if none are available
+ *     or IOC is not active.
+ */
+MPT_FRAME_HDR*
+mpt_get_msg_frame(int handle, int iocid)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       MPT_ADAPTER *iocp;
+       unsigned long flags;
+
+       /* validate handle and ioc identifier */
+       iocp = mpt_adapters[iocid];
+
+#ifdef MFCNT
+       if (!iocp->active)
+               printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+#endif
+
+       /* If interrupts are not attached, do not return a request frame */
+       if (!iocp->active)
+               return NULL;
+
+       spin_lock_irqsave(&iocp->FreeQlock, flags);
+       if (! Q_IS_EMPTY(&iocp->FreeQ)) {
+               int req_offset;
+
+               mf = iocp->FreeQ.head;
+               Q_DEL_ITEM(&mf->u.frame.linkage);
+               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;  /* byte */
+               req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+                                                               /* u16! */
+               mf->u.frame.hwhdr.msgctxu.fld.req_idx =
+                               cpu_to_le16(req_offset / iocp->req_sz);
+               mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+#ifdef MFCNT
+               iocp->mfcnt++;
+#endif
+       }
+       spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+
+#ifdef MFCNT
+       if (mf == NULL)
+               printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth);
+       mfcounter++;
+       if (mfcounter == PRINT_MF_COUNT)
+               printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth);
+#endif
+
+       return mf;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_put_msg_frame - Send a protocol specific MPT request frame
+ *     to a IOC.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *     @mf: Pointer to MPT request frame
+ *
+ *     This routine posts a MPT request frame to the request post FIFO of a
+ *     specific MPT adapter.
+ */
+void
+mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+       MPT_ADAPTER *iocp;
+
+       iocp = mpt_adapters[iocid];
+       if (iocp != NULL) {
+               u32 mf_dma_addr;
+               int req_offset;
+
+               /* ensure values are reset properly! */
+               mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;          /* byte */
+               req_offset = (u8 *)mf - (u8 *)iocp->req_frames;
+                                                                       /* u16! */
+               mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz);
+               mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+#ifdef MPT_DEBUG_MSG_FRAME
+               {
+                       u32     *m = mf->u.frame.hwhdr.__hdr;
+                       int      ii, n;
+
+                       printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
+                                       iocp->name, m);
+                       n = iocp->req_sz/4 - 1;
+                       while (m[n] == 0)
+                               n--;
+                       for (ii=0; ii<=n; ii++) {
+                               if (ii && ((ii%8)==0))
+                                       printk("\n" KERN_INFO " ");
+                               printk(" %08x", le32_to_cpu(m[ii]));
+                       }
+                       printk("\n");
+               }
+#endif
+
+               mf_dma_addr = iocp->req_frames_low_dma + req_offset;
+               CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_free_msg_frame - Place MPT request frame back on FreeQ.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *     @mf: Pointer to MPT request frame
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+void
+mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf)
+{
+       MPT_ADAPTER *iocp;
+       unsigned long flags;
+
+       iocp = mpt_adapters[iocid];
+       if (iocp != NULL) {
+               /*  Put Request back on FreeQ!  */
+               spin_lock_irqsave(&iocp->FreeQlock, flags);
+               Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+               iocp->mfcnt--;
+#endif
+               spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_sge - Place a simple SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+void
+mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
+
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pSge->Address.High = cpu_to_le32(tmp);
+
+       } else {
+               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address = cpu_to_le32(dma_addr);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_add_chain - Place a chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+void
+mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
+
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+
+               pChain->NextChainOffset = next;
+
+               pChain->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pChain->Address.High = cpu_to_le32(tmp);
+       } else {
+               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+               pChain->NextChainOffset = next;
+               pChain->Address = cpu_to_le32(dma_addr);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_send_handshake_request - Send MPT request via doorbell
+ *     handshake method.
+ *     @handle: Handle of registered MPT protocol driver
+ *     @iocid: IOC unique identifier (integer)
+ *     @reqBytes: Size of the request in bytes
+ *     @req: Pointer to MPT request frame
+ *     @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
+ *
+ *     This routine is used exclusively to send MptScsiTaskMgmt
+ *     requests since they are required to be sent via doorbell handshake.
+ *
+ *     NOTE: It is the callers responsibility to byte-swap fields in the
+ *     request which are greater than 1 byte in size.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+int
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag)
+{
+       MPT_ADAPTER     *iocp;
+       int              r = 0;
+
+       iocp = mpt_adapters[iocid];
+       if (iocp != NULL) {
+               u8      *req_as_bytes;
+               int      ii;
+
+               /* State is known to be good upon entering
+                * this function so issue the bus reset
+                * request.
+                */
+
+               /*
+                * Emulate what mpt_put_msg_frame() does /wrt to sanity
+                * setting cb_idx/req_idx.  But ONLY if this request
+                * is in proper (pre-alloc'd) request buffer range...
+                */
+               ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+               if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) {
+                       MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
+                       mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
+                       mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+               }
+
+               /* Make sure there are no doorbells */
+               CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+               CHIPREG_WRITE32(&iocp->chip->Doorbell,
+                               ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+                                ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+               /* Wait for IOC doorbell int */
+               if ((ii = WaitForDoorbellInt(iocp, 2, sleepFlag)) < 0) {
+                       return ii;
+               }
+
+               /* Read doorbell and check for active bit */
+               if (!(CHIPREG_READ32(&iocp->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+                               return -5;
+
+               dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+                               iocp->name, ii));
+
+               CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+
+               if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) {
+                       return -2;
+               }
+
+               /* Send request via doorbell handshake */
+               req_as_bytes = (u8 *) req;
+               for (ii = 0; ii < reqBytes/4; ii++) {
+                       u32 word;
+
+                       word = ((req_as_bytes[(ii*4) + 0] <<  0) |
+                               (req_as_bytes[(ii*4) + 1] <<  8) |
+                               (req_as_bytes[(ii*4) + 2] << 16) |
+                               (req_as_bytes[(ii*4) + 3] << 24));
+                       CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
+                       if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) {
+                               r = -3;
+                               break;
+                       }
+               }
+
+               if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0)
+                       r = 0;
+               else
+                       r = -4;
+
+               /* Make sure there are no doorbells */
+               CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+       }
+
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_adapter_find_first - Find first MPT adapter pointer.
+ *
+ *     Returns first MPT adapter pointer or %NULL if no MPT adapters
+ *     are present.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_first(void)
+{
+       MPT_ADAPTER *this = NULL;
+
+       if (! Q_IS_EMPTY(&MptAdapters))
+               this = MptAdapters.head;
+
+       return this;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_adapter_find_next - Find next MPT adapter pointer.
+ *     @prev: Pointer to previous MPT adapter
+ *
+ *     Returns next MPT adapter pointer or %NULL if there are no more.
+ */
+MPT_ADAPTER *
+mpt_adapter_find_next(MPT_ADAPTER *prev)
+{
+       MPT_ADAPTER *next = NULL;
+
+       if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head))
+               next = prev->forw;
+
+       return next;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_pci_scan - Scan PCI devices for MPT adapters.
+ *
+ *     Returns count of MPT adapters found, keying off of PCI vendor and
+ *     device_id's.
+ */
+static int __init
+mpt_pci_scan(void)
+{
+       struct pci_dev *pdev;
+       struct pci_dev *pdev2;
+       int found = 0;
+       int count = 0;
+       int r;
+
+       dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
+
+       /*
+        *  NOTE: The 929, 929X, 1030 and 1035 will appear as 2 separate PCI devices,
+        *  one for each channel.
+        */
+       pci_for_each_dev(pdev) {
+               pdev2 = NULL;
+               if (pdev->vendor != 0x1000)
+                       continue;
+
+               if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929X) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919X) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
+                   (pdev->device != MPI_MANUFACTPAGE_DEVID_1030_53C1035) &&
+                   1) {
+                       dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device));
+                       continue;
+               }
+
+               /* GRRRRR
+                * dual function devices (929, 929X, 1030, 1035) may be presented in Func 1,0 order,
+                * but we'd really really rather have them in Func 0,1 order.
+                * Do some kind of look ahead here...
+                */
+               if (pdev->devfn & 1) {
+                       /* SAE: Not a clear macro */
+                       pdev2 = NULL;
+                       if(pdev != pci_dev_g(&pci_devices))
+                               pdev2 = pci_dev_g(pdev->global_list.next);
+
+                       if (pdev2 && (pdev2->vendor == 0x1000) &&
+                           (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
+                           (pdev2->device == pdev->device) &&
+                           (pdev2->bus->number == pdev->bus->number) &&
+                           !(pdev2->devfn & 1)) {
+                               dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+                                       pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
+                               found++;
+                               if ((r = mpt_adapter_install(pdev2)) == 0)
+                                       count++;
+                       } else {
+                               pdev2 = NULL;
+                       }
+               }
+
+               dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
+                        pdev->bus->number, pdev->devfn, pdev->class, pdev->device));
+               found++;
+               if ((r = mpt_adapter_install(pdev)) == 0)
+                       count++;
+
+               if (pdev2)
+                       pdev = pdev2;
+       }
+
+       if (!found || !count) {
+               fusion_exit();
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n",
+                found, (found==1) ? "" : "s", count);
+
+#ifdef CONFIG_PROC_FS
+       (void) procmpt_create();
+#endif
+
+       return count;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_verify_adapter - Given a unique IOC identifier, set pointer to
+ *     the associated MPT adapter structure.
+ *     @iocid: IOC unique identifier (integer)
+ *     @iocpp: Pointer to pointer to IOC adapter
+ *
+ *     Returns iocid and sets iocpp.
+ */
+int
+mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
+{
+       MPT_ADAPTER *p;
+
+       *iocpp = NULL;
+       if (iocid >= MPT_MAX_ADAPTERS)
+               return -1;
+
+       p = mpt_adapters[iocid];
+       if (p == NULL)
+               return -1;
+
+       *iocpp = p;
+       return iocid;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_adapter_install - Install a PCI intelligent MPT adapter.
+ *     @pdev: Pointer to pci_dev structure
+ *
+ *     This routine performs all the steps necessary to bring the IOC of
+ *     a MPT adapter to a OPERATIONAL state.  This includes registering
+ *     memory regions, registering the interrupt, and allocating request
+ *     and reply memory pools.
+ *
+ *     This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ *     MPT adapter.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ *
+ *     TODO: Add support for polled controllers
+ */
+static int __init
+mpt_adapter_install(struct pci_dev *pdev)
+{
+       MPT_ADAPTER     *ioc;
+       u8              *mem;
+       unsigned long    mem_phys;
+       unsigned long    port;
+       u32              msize;
+       u32              psize;
+       int              ii;
+       int              r = -ENODEV;
+       u64              mask = 0xffffffffffffffffULL;
+
+       if (pci_enable_device(pdev))
+               return r;
+
+       if (!pci_set_dma_mask(pdev, mask)) {
+               dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+       } else {
+               if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
+                       printk(KERN_WARNING MYNAM
+                               ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+                       return r;
+               }
+       }
+
+       ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+       if (ioc == NULL) {
+               printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+               return -ENOMEM;
+       }
+       memset(ioc, 0, sizeof(*ioc));
+       ioc->alloc_total = sizeof(MPT_ADAPTER);
+       ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
+       ioc->reply_sz = ioc->req_sz;
+
+       ioc->pcidev = pdev;
+       ioc->diagPending = 0;
+       spin_lock_init(&ioc->diagLock);
+
+       /* Initialize the event logging.
+        */
+       ioc->eventTypes = 0;    /* None */
+       ioc->eventContext = 0;
+       ioc->eventLogSize = 0;
+       ioc->events = NULL;
+
+#ifdef MFCNT
+       ioc->mfcnt = 0;
+#endif
+
+       ioc->cached_fw = NULL;
+
+       /* Initilize SCSI Config Data structure
+        */
+       memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
+
+       /* Initialize the running configQ head.
+        */
+       Q_INIT(&ioc->configQ, Q_ITEM);
+
+       /* Find lookup slot. */
+       for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) {
+               if (mpt_adapters[ii] == NULL) {
+                       ioc->id = ii;           /* Assign adapter unique id (lookup) */
+                       break;
+               }
+       }
+       if (ii == MPT_MAX_ADAPTERS) {
+               printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii);
+               kfree(ioc);
+               return -ENFILE;
+       }
+
+       mem_phys = msize = 0;
+       port = psize = 0;
+       for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
+               /* SAE: Why not assume Linux 2.4? */
+               if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
+                       /* Get I/O space! */
+                       port = pci_resource_start(pdev, ii);
+                       psize = pci_resource_len(pdev, ii);
+               } else {
+                       /* Get memmap */
+                       mem_phys = pci_resource_start(pdev, ii);
+                       msize = pci_resource_len(pdev, ii);
+                       break;
+               }
+       }
+       ioc->mem_size = msize;
+
+       if (ii == DEVICE_COUNT_RESOURCE) {
+               printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
+               kfree(ioc);
+               return -EINVAL;
+       }
+
+       dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
+       dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
+       dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap"));
+
+       mem = NULL;
+       if (! PortIo) {
+               /* Get logical ptr for PciMem0 space */
+               /*mem = ioremap(mem_phys, msize);*/
+               mem = ioremap(mem_phys, 0x100);
+               if (mem == NULL) {
+                       printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+                       kfree(ioc);
+                       return -EINVAL;
+               }
+               ioc->memmap = mem;
+       }
+       dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+
+       dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
+                       &ioc->facts, &ioc->pfacts[0]));
+       if (PortIo) {
+               u8 *pmem = (u8*)port;
+               ioc->mem_phys = port;
+               ioc->chip = (SYSIF_REGS*)pmem;
+       } else {
+               ioc->mem_phys = mem_phys;
+               ioc->chip = (SYSIF_REGS*)mem;
+       }
+
+       /* Save Port IO values incase we need to do downloadboot */
+       {
+               u8 *pmem = (u8*)port;
+               ioc->pio_mem_phys = port;
+               ioc->pio_chip = (SYSIF_REGS*)pmem;
+       }
+
+       ioc->chip_type = FCUNK;
+       if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
+               ioc->chip_type = FC909;
+               ioc->prod_name = "LSIFC909";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
+               ioc->chip_type = FC929;
+               ioc->prod_name = "LSIFC929";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
+               ioc->chip_type = FC919;
+               ioc->prod_name = "LSIFC919";
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
+               ioc->chip_type = FC929X;
+               ioc->prod_name = "LSIFC929X";
+               {
+                       /* 929X Chip Fix. Set Split transactions level
+                        * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+                        */
+                       u16 pcixcmd = 0;
+                       pci_read_config_word(pdev, 0x6a, &pcixcmd);
+                       pcixcmd &= 0xFF9F;
+                       pcixcmd |= 0x0010;
+                       pci_write_config_word(pdev, 0x6a, pcixcmd);
+               }
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
+               ioc->chip_type = FC919X;
+               ioc->prod_name = "LSIFC919X";
+               {
+                       /* 919X Chip Fix. Set Split transactions level
+                        * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+                        */
+                       u16 pcixcmd = 0;
+                       pci_read_config_word(pdev, 0x6a, &pcixcmd);
+                       pcixcmd &= 0xFF9F;
+                       pcixcmd |= 0x0010;
+                       pci_write_config_word(pdev, 0x6a, pcixcmd);
+               }
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
+               ioc->chip_type = C1030;
+               ioc->prod_name = "LSI53C1030";
+               {
+                       u8 revision;
+
+                       /* 1030 Chip Fix. Disable Split transactions
+                        * for PCIX. Set bits 4 - 6 to zero if Rev < C0( = 8)
+                        */
+                       pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+                       if (revision < 0x08) {
+                               u16 pcixcmd = 0;
+                               pci_read_config_word(pdev, 0x6a, &pcixcmd);
+                               pcixcmd &= 0xFF8F;
+                               pci_write_config_word(pdev, 0x6a, pcixcmd);
+                       }
+               }
+       }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
+               ioc->chip_type = C1035;
+               ioc->prod_name = "LSI53C1035";
+       }
+
+       sprintf(ioc->name, "ioc%d", ioc->id);
+
+       Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+       spin_lock_init(&ioc->FreeQlock);
+
+       /* Disable all! */
+       CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+       ioc->active = 0;
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+       /* tack onto tail of our MPT adapter list */
+       Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
+
+       /* Set lookup ptr. */
+       mpt_adapters[ioc->id] = ioc;
+
+       ioc->pci_irq = -1;
+       if (pdev->irq) {
+               r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
+
+               if (r < 0) {
+#ifndef __sparc__
+                       printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
+                                       ioc->name, pdev->irq);
+#else
+                       printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
+                                       ioc->name, __irq_itoa(pdev->irq));
+#endif
+                       Q_DEL_ITEM(ioc);
+                       mpt_adapters[ioc->id] = NULL;
+                       iounmap(mem);
+                       kfree(ioc);
+                       return -EBUSY;
+               }
+
+               ioc->pci_irq = pdev->irq;
+
+               pci_set_master(pdev);                   /* ?? */
+
+#ifndef __sparc__
+               dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+#else
+               dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
+#endif
+       }
+
+       /* NEW!  20010220 -sralston
+        * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
+        */
+       if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)
+                       || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X))
+               mpt_detect_bound_ports(ioc, pdev);
+
+       if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
+               printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
+                               ioc->name, r);
+       }
+
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_do_ioc_recovery - Initialize or recover MPT adapter.
+ *     @ioc: Pointer to MPT adapter structure
+ *     @reason: Event word / reason
+ *     @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
+ *
+ *     This routine performs all the steps necessary to bring the IOC
+ *     to a OPERATIONAL state.
+ *
+ *     This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ *     MPT adapter.
+ *
+ *     Returns:
+ *              0 for success
+ *             -1 if failed to get board READY
+ *             -2 if READY but IOCFacts Failed
+ *             -3 if READY but PrimeIOCFifos Failed
+ *             -4 if READY but IOCInit Failed
+ */
+static int
+mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
+{
+       int      hard_reset_done = 0;
+       int      alt_ioc_ready = 0;
+       int      hard;
+       int      r;
+       int      ii;
+       int      handlers;
+       int      ret = 0;
+       int      reset_alt_ioc_active = 0;
+
+       printk(KERN_INFO MYNAM ": Initiating %s %s\n",
+                       ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
+
+       /* Disable reply interrupts (also blocks FreeQ) */
+       CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+       ioc->active = 0;
+
+       if (ioc->alt_ioc) {
+               if (ioc->alt_ioc->active)
+                       reset_alt_ioc_active = 1;
+
+               /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
+               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
+               ioc->alt_ioc->active = 0;
+       }
+
+       hard = 1;
+       if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
+               hard = 0;
+
+       if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
+               if (hard_reset_done == -4) {
+                       printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
+                                       ioc->name);
+
+                       if (reset_alt_ioc_active && ioc->alt_ioc) {
+                               /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
+                               dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+                                               ioc->alt_ioc->name));
+                               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+                               ioc->alt_ioc->active = 1;
+                       }
+
+               } else {
+                       printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
+                                       ioc->name);
+               }
+               return -1;
+       }
+
+       /* hard_reset_done = 0 if a soft reset was performed
+        * and 1 if a hard reset was performed.
+        */
+       if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
+               if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
+                       alt_ioc_ready = 1;
+               else
+                       printk(KERN_WARNING MYNAM
+                                       ": alt-%s: (%d) Not ready WARNING!\n",
+                                       ioc->alt_ioc->name, r);
+       }
+
+       /* Get IOC facts! Allow 1 retry */
+       if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
+               r = GetIocFacts(ioc, sleepFlag, reason);
+
+       if (r) {
+               ret = -2;
+       } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+               MptDisplayIocCapabilities(ioc);
+       }
+
+       if (alt_ioc_ready) {
+               if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
+                       /* Retry - alt IOC was initialized once
+                        */
+                       r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
+               }
+               if (r) {
+                       alt_ioc_ready = 0;
+                       reset_alt_ioc_active = 0;
+               } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+                       MptDisplayIocCapabilities(ioc->alt_ioc);
+               }
+       }
+
+       /* Prime reply & request queues!
+        * (mucho alloc's) Must be done prior to
+        * init as upper addresses are needed for init.
+        * If fails, continue with alt-ioc processing
+        */
+       if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0))
+               ret = -3;
+
+       /* May need to check/upload firmware & data here!
+        * If fails, continue with alt-ioc processing
+        */
+       if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0))
+               ret = -4;
+// NEW!
+       if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
+               printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
+                               ioc->alt_ioc->name, r);
+               alt_ioc_ready = 0;
+               reset_alt_ioc_active = 0;
+       }
+
+       if (alt_ioc_ready) {
+               if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
+                       alt_ioc_ready = 0;
+                       reset_alt_ioc_active = 0;
+                       printk(KERN_WARNING MYNAM
+                               ": alt-%s: (%d) init failure WARNING!\n",
+                                       ioc->alt_ioc->name, r);
+               }
+       }
+
+       if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
+               if (ioc->upload_fw) {
+                       ddlprintk((MYIOC_s_INFO_FMT
+                               "firmware upload required!\n", ioc->name));
+
+                       /* Controller is not operational, cannot do upload
+                        */
+                       if (ret == 0) {
+                               r = mpt_do_upload(ioc, sleepFlag);
+                               if (r != 0)
+                                       printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+                       }
+
+                       /* Handle the alt IOC too */
+                       if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
+                               ddlprintk((MYIOC_s_INFO_FMT
+                                       "Alt-ioc firmware upload required!\n",
+                                       ioc->name));
+                               r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
+                               if (r != 0)
+                                       printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+                       }
+               }
+       }
+
+       if (ret == 0) {
+               /* Enable! (reply interrupt) */
+               CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+               ioc->active = 1;
+       }
+
+       if (reset_alt_ioc_active && ioc->alt_ioc) {
+               /* (re)Enable alt-IOC! (reply interrupt) */
+               dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+                               ioc->alt_ioc->name));
+               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+               ioc->alt_ioc->active = 1;
+       }
+
+       /* NEW!  20010120 -sralston
+        *  Enable MPT base driver management of EventNotification
+        *  and EventAck handling.
+        */
+       if ((ret == 0) && (!ioc->facts.EventState))
+               (void) SendEventNotification(ioc, 1);   /* 1=Enable EventNotification */
+
+       if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+               (void) SendEventNotification(ioc->alt_ioc, 1);  /* 1=Enable EventNotification */
+
+       /* (Bugzilla:fibrebugs, #513)
+        * Bug fix (part 2)!  20010905 -sralston
+        *      Add additional "reason" check before call to GetLanConfigPages
+        *      (combined with GetIoUnitPage2 call).  This prevents a somewhat
+        *      recursive scenario; GetLanConfigPages times out, timer expired
+        *      routine calls HardResetHandler, which calls into here again,
+        *      and we try GetLanConfigPages again...
+        */
+       if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
+               if ((int)ioc->chip_type <= (int)FC929) {
+                       /*
+                        *  Pre-fetch FC port WWN and stuff...
+                        *  (FCPortPage0_t stuff)
+                        */
+                       for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+                               (void) GetFcPortPage0(ioc, ii);
+                       }
+
+                       if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+                           (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
+                               /*
+                                *  Pre-fetch the ports LAN MAC address!
+                                *  (LANPage1_t stuff)
+                                */
+                               (void) GetLanConfigPages(ioc);
+#ifdef MPT_DEBUG
+                               {
+                                       u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+                                       dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                                       ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+                               }
+#endif
+                       }
+               } else {
+                       /* Get NVRAM and adapter maximums from SPP 0 and 2
+                        */
+                       mpt_GetScsiPortSettings(ioc, 0);
+
+                       /* Get version and length of SDP 1
+                        */
+                       mpt_readScsiDevicePageHeaders(ioc, 0);
+
+                       /* Find IM volumes
+                        */
+                       if (ioc->facts.MsgVersion >= 0x0102)
+                               mpt_findImVolumes(ioc);
+
+                       /* Check, and possibly reset, the coalescing value
+                        */
+                       mpt_read_ioc_pg_1(ioc);
+               }
+
+               GetIoUnitPage2(ioc);
+       }
+
+       /*
+        * Call each currently registered protocol IOC reset handler
+        * with post-reset indication.
+        * NOTE: If we're doing _IOC_BRINGUP, there can be no
+        * MptResetHandlers[] registered yet.
+        */
+       if (hard_reset_done) {
+               r = handlers = 0;
+               for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+                       if ((ret == 0) && MptResetHandlers[ii]) {
+                               dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
+                                               ioc->name, ii));
+                               r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
+                               handlers++;
+                       }
+
+                       if (alt_ioc_ready && MptResetHandlers[ii]) {
+                               dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+                                               ioc->name, ioc->alt_ioc->name, ii));
+                               r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+                               handlers++;
+                       }
+               }
+               /* FIXME?  Examine results here? */
+       }
+
+       return ret;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_detect_bound_ports - Search for PCI bus/dev_function
+ *     which matches PCI bus/dev_function (+/-1) for newly discovered 929,
+ *     929X, 1030 or 1035.
+ *     @ioc: Pointer to MPT adapter structure
+ *     @pdev: Pointer to (struct pci_dev) structure
+ *
+ *     If match on PCI dev_function +/-1 is found, bind the two MPT adapters
+ *     using alt_ioc pointer fields in their %MPT_ADAPTER structures.
+ */
+static void
+mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+{
+       MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
+       unsigned int match_lo, match_hi;
+
+       match_lo = pdev->devfn-1;
+       match_hi = pdev->devfn+1;
+       dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
+                       ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
+
+       while (ioc_srch != NULL) {
+               struct pci_dev *_pcidev = ioc_srch->pcidev;
+
+               if ((_pcidev->device == pdev->device) &&
+                   (_pcidev->bus->number == pdev->bus->number) &&
+                   (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+                       /* Paranoia checks */
+                       if (ioc->alt_ioc != NULL) {
+                               printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+                                               ioc->name, ioc->alt_ioc->name);
+                               break;
+                       } else if (ioc_srch->alt_ioc != NULL) {
+                               printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+                                               ioc_srch->name, ioc_srch->alt_ioc->name);
+                               break;
+                       }
+                       dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+                                       ioc->name, ioc_srch->name));
+                       ioc_srch->alt_ioc = ioc;
+                       ioc->alt_ioc = ioc_srch;
+                       break;
+               }
+               ioc_srch = mpt_adapter_find_next(ioc_srch);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_adapter_disable - Disable misbehaving MPT adapter.
+ *     @this: Pointer to MPT adapter structure
+ *     @free: Free up alloc'd reply, request, etc.
+ */
+static void
+mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
+{
+       if (this != NULL) {
+               int sz;
+               u32 state;
+               int ret;
+
+               /* Disable the FW */
+               state = mpt_GetIocState(this, 1);
+               if (state == MPI_IOC_STATE_OPERATIONAL) {
+                       SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP);
+               }
+
+               if (this->cached_fw != NULL) {
+                       ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
+
+                       if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) {
+                               printk(KERN_WARNING MYNAM
+                                       ": firmware downloadboot failure (%d)!\n", ret);
+                       }
+               }
+
+               /* Disable adapter interrupts! */
+               CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+               this->active = 0;
+               /* Clear any lingering interrupt */
+               CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+
+               if (freeup && this->reply_alloc != NULL) {
+                       sz = (this->reply_sz * this->reply_depth) + 128;
+                       pci_free_consistent(this->pcidev, sz,
+                                       this->reply_alloc, this->reply_alloc_dma);
+                       this->reply_frames = NULL;
+                       this->reply_alloc = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->req_alloc != NULL) {
+                       sz = (this->req_sz * this->req_depth) + 128;
+                       /*
+                        *  Rounding UP to nearest 4-kB boundary here...
+                        */
+                       sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+                       pci_free_consistent(this->pcidev, sz,
+                                       this->req_alloc, this->req_alloc_dma);
+                       this->req_frames = NULL;
+                       this->req_alloc = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->sense_buf_pool != NULL) {
+                       sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC);
+                       pci_free_consistent(this->pcidev, sz,
+                                       this->sense_buf_pool, this->sense_buf_pool_dma);
+                       this->sense_buf_pool = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->events != NULL){
+                       sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+                       kfree(this->events);
+                       this->events = NULL;
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->cached_fw != NULL) {
+                       int ii = 0;
+
+                       while ((ii < this->num_fw_frags) && (this->cached_fw[ii]!= NULL)) {
+                               sz = this->cached_fw[ii]->size;
+                               pci_free_consistent(this->pcidev, sz,
+                                       this->cached_fw[ii]->fw, this->cached_fw[ii]->fw_dma);
+                               this->cached_fw[ii]->fw = NULL;
+                               this->alloc_total -= sz;
+
+                               kfree(this->cached_fw[ii]);
+                               this->cached_fw[ii] = NULL;
+                               this->alloc_total -= sizeof(fw_image_t);
+
+                               ii++;
+                       }
+
+                       kfree(this->cached_fw);
+                       this->cached_fw = NULL;
+                       sz = this->num_fw_frags * sizeof(void *);
+                       this->alloc_total -= sz;
+               }
+
+               if (freeup && this->spi_data.nvram != NULL) {
+                       kfree(this->spi_data.nvram);
+                       this->spi_data.nvram = NULL;
+               }
+
+               if (freeup && this->spi_data.pIocPg3 != NULL) {
+                       kfree(this->spi_data.pIocPg3);
+                       this->spi_data.pIocPg3 = NULL;
+               }
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_adapter_dispose - Free all resources associated with a MPT
+ *     adapter.
+ *     @this: Pointer to MPT adapter structure
+ *
+ *     This routine unregisters h/w resources and frees all alloc'd memory
+ *     associated with a MPT adapter structure.
+ */
+static void
+mpt_adapter_dispose(MPT_ADAPTER *this)
+{
+       if (this != NULL) {
+               int sz_first, sz_last;
+
+               sz_first = this->alloc_total;
+
+               if (this->alt_ioc != NULL) {
+                       this->alt_ioc->alt_ioc = NULL;
+                       this->alt_ioc = NULL;
+               }
+
+               mpt_adapter_disable(this, 1);
+
+               if (this->pci_irq != -1) {
+                       free_irq(this->pci_irq, this);
+                       this->pci_irq = -1;
+               }
+
+               if (this->memmap != NULL)
+                       iounmap((u8 *) this->memmap);
+
+#if defined(CONFIG_MTRR) && 0
+               if (this->mtrr_reg > 0) {
+                       mtrr_del(this->mtrr_reg, 0, 0);
+                       dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name));
+               }
+#endif
+
+               /*  Zap the adapter lookup ptr!  */
+               mpt_adapters[this->id] = NULL;
+
+               sz_last = this->alloc_total;
+               dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+                               this->name, sz_first-sz_last+(int)sizeof(*this), sz_first));
+               kfree(this);
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     MptDisplayIocCapabilities - Disply IOC's capacilities.
+ *     @ioc: Pointer to MPT adapter structure
+ */
+static void
+MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
+{
+       int i = 0;
+
+       printk(KERN_INFO "%s: ", ioc->name);
+       if (ioc->prod_name && strlen(ioc->prod_name) > 3)
+               printk("%s: ", ioc->prod_name+3);
+       printk("Capabilities={");
+
+       if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
+               printk("Initiator");
+               i++;
+       }
+
+       if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+               printk("%sTarget", i ? "," : "");
+               i++;
+       }
+
+       if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+               printk("%sLAN", i ? "," : "");
+               i++;
+       }
+
+#if 0
+       /*
+        *  This would probably evoke more questions than it's worth
+        */
+       if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+               printk("%sLogBusAddr", i ? "," : "");
+               i++;
+       }
+#endif
+
+       printk("}\n");
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     MakeIocReady - Get IOC to a READY state, using KickStart if needed.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @force: Force hard KickStart of IOC
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     Returns:
+ *              1 - DIAG reset and READY
+ *              0 - READY initially OR soft reset and READY
+ *             -1 - Any failure on KickStart
+ *             -2 - Msg Unit Reset Failed
+ *             -3 - IO Unit Reset Failed
+ *             -4 - IOC owned by a PEER
+ */
+static int
+MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
+{
+       u32      ioc_state;
+       int      statefault = 0;
+       int      cntdn;
+       int      hard_reset_done = 0;
+       int      r;
+       int      ii;
+       int      whoinit;
+
+       /* Get current [raw] IOC state  */
+       ioc_state = mpt_GetIocState(ioc, 0);
+       dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+
+       /*
+        *      Check to see if IOC got left/stuck in doorbell handshake
+        *      grip of death.  If so, hard reset the IOC.
+        */
+       if (ioc_state & MPI_DOORBELL_ACTIVE) {
+               statefault = 1;
+               printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
+                               ioc->name);
+       }
+
+       /* Is it already READY? */
+       if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) {
+               if ((int)ioc->chip_type <= (int)FC929)
+                       return 0;
+               else {
+                       /* Workaround from broken 1030 FW.
+                        * Force a diagnostic reset if fails.
+                        */
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+                               return 0;
+                       else
+                               statefault = 4;
+               }
+       }
+
+       /*
+        *      Check to see if IOC is in FAULT state.
+        */
+       if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+               statefault = 2;
+               printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
+                               ioc->name);
+               printk(KERN_WARNING "           FAULT code = %04xh\n",
+                               ioc_state & MPI_DOORBELL_DATA_MASK);
+       }
+
+       /*
+        *      Hmmm...  Did it get left operational?
+        */
+       if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
+               dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
+                               ioc->name));
+
+               /* Check WhoInit.
+                * If PCI Peer, exit.
+                * Else, if no fault conditions are present, issue a MessageUnitReset
+                * Else, fall through to KickStart case
+                */
+               whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
+               dprintk((KERN_WARNING MYNAM
+                       ": whoinit 0x%x\n statefault %d force %d\n",
+                       whoinit, statefault, force));
+               if (whoinit == MPI_WHOINIT_PCI_PEER)
+                       return -4;
+               else {
+                       if ((statefault == 0 ) && (force == 0)) {
+                               if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+                                       return 0;
+                       }
+                       statefault = 3;
+               }
+       }
+
+       hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
+       if (hard_reset_done < 0)
+               return -1;
+
+       /*
+        *  Loop here waiting for IOC to come READY.
+        */
+       ii = 0;
+       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15;    /* 15 seconds */
+
+       while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+               if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
+                       /*
+                        *  BIOS or previous driver load left IOC in OP state.
+                        *  Reset messaging FIFOs.
+                        */
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
+                               printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
+                               return -2;
+                       }
+               } else if (ioc_state == MPI_IOC_STATE_RESET) {
+                       /*
+                        *  Something is wrong.  Try to get IOC back
+                        *  to a known state.
+                        */
+                       if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
+                               printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
+                               return -3;
+                       }
+               }
+
+               ii++; cntdn--;
+               if (!cntdn) {
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+                                       ioc->name, (ii+5)/HZ);
+                       return -ETIME;
+               }
+
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+               } else {
+                       mdelay (1);     /* 1 msec delay */
+               }
+
+       }
+
+       if (statefault < 3) {
+               printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
+                               ioc->name,
+                               statefault==1 ? "stuck handshake" : "IOC FAULT");
+       }
+
+       return hard_reset_done;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_GetIocState - Get the current state of a MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @cooked: Request raw or cooked IOC state
+ *
+ *     Returns all IOC Doorbell register bits if cooked==0, else just the
+ *     Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+u32
+mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
+{
+       u32 s, sc;
+
+       /*  Get!  */
+       s = CHIPREG_READ32(&ioc->chip->Doorbell);
+//     dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
+       sc = s & MPI_IOC_STATE_MASK;
+
+       /*  Save!  */
+       ioc->last_state = sc;
+
+       return cooked ? sc : s;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetIocFacts - Send IOCFacts request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Specifies whether the process can sleep
+ *     @reason: If recovery, only update facts.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
+{
+       IOCFacts_t               get_facts;
+       IOCFactsReply_t         *facts;
+       int                      r;
+       int                      req_sz;
+       int                      reply_sz;
+       u32                      status;
+       
+       /* IOC *must* NOT be in RESET state! */
+       if (ioc->last_state == MPI_IOC_STATE_RESET) {
+               printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
+                               ioc->name,
+                               ioc->last_state );
+               return -44;
+       }
+
+       facts = &ioc->facts;
+
+       /* Destination (reply area)... */
+       reply_sz = sizeof(*facts);
+       memset(facts, 0, reply_sz);
+
+       /* Request area (get_facts on the stack right now!) */
+       req_sz = sizeof(get_facts);
+       memset(&get_facts, 0, req_sz);
+
+       get_facts.Function = MPI_FUNCTION_IOC_FACTS;
+       /* Assert: All other get_facts fields are zero! */
+
+       dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name));
+
+       /* No non-zero fields in the get_facts request are greater than
+        * 1 byte in size, so we can just fire it off as is.
+        */
+       r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
+                       reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag);
+       if (r != 0)
+               return r;
+
+       /*
+        * Now byte swap (GRRR) the necessary fields before any further
+        * inspection of reply contents.
+        *
+        * But need to do some sanity checks on MsgLength (byte) field
+        * to make sure we don't zero IOC's req_sz!
+        */
+       /* Did we get a valid reply? */
+       if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
+               if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+                       /*
+                        * If not been here, done that, save off first WhoInit value
+                        */
+                       if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
+                               ioc->FirstWhoInit = facts->WhoInit;
+               }
+
+               facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
+               facts->MsgContext = le32_to_cpu(facts->MsgContext);
+               facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
+               facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
+               facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
+               status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
+               /* CHECKME! IOCStatus, IOCLogInfo */
+
+               facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
+               facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
+
+               /*
+                * FC f/w version changed between 1.1 and 1.2
+                *      Old: u16{Major(4),Minor(4),SubMinor(8)}
+                *      New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
+                */
+               if (facts->MsgVersion < 0x0102) {
+                       /*
+                        *      Handle old FC f/w style, convert to new...
+                        */
+                       u16      oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
+                       facts->FWVersion.Word =
+                                       ((oldv<<12) & 0xFF000000) |
+                                       ((oldv<<8)  & 0x000FFF00);
+               } else
+                       facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
+
+               facts->ProductID = le16_to_cpu(facts->ProductID);
+               facts->CurrentHostMfaHighAddr =
+                               le32_to_cpu(facts->CurrentHostMfaHighAddr);
+               facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
+               facts->CurrentSenseBufferHighAddr =
+                               le32_to_cpu(facts->CurrentSenseBufferHighAddr);
+               facts->CurReplyFrameSize =
+                               le16_to_cpu(facts->CurReplyFrameSize);
+
+               /*
+                * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
+                * Older MPI-1.00.xx struct had 13 dwords, and enlarged
+                * to 14 in MPI-1.01.0x.
+                */
+               if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
+                   facts->MsgVersion > 0x0100) {
+                       facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
+               }
+
+               if (!facts->RequestFrameSize) {
+                       /*  Something is wrong!  */
+                       printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
+                                       ioc->name);
+                       return -55;
+               }
+
+               if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+                       /*
+                        * Set values for this IOC's request & reply frame sizes,
+                        * and request & reply queue depths...
+                        */
+                       ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
+                       ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
+                       ioc->reply_sz = ioc->req_sz;
+                       ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+                       dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
+                               ioc->name, ioc->reply_sz, ioc->reply_depth));
+                       dprintk((MYIOC_s_INFO_FMT "req_sz  =%3d, req_depth  =%4d\n",
+                               ioc->name, ioc->req_sz, ioc->req_depth));
+
+                       /* Get port facts! */
+                       if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
+                               return r;
+               }
+       } else {
+               printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n",
+                               ioc->name);
+               return -66;
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetPortFacts - Send PortFacts request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @portnum: Port number
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
+{
+       PortFacts_t              get_pfacts;
+       PortFactsReply_t        *pfacts;
+       int                      ii;
+       int                      req_sz;
+       int                      reply_sz;
+
+       /* IOC *must* NOT be in RESET state! */
+       if (ioc->last_state == MPI_IOC_STATE_RESET) {
+               printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
+                               ioc->name,
+                               ioc->last_state );
+               return -4;
+       }
+
+       pfacts = &ioc->pfacts[portnum];
+
+       /* Destination (reply area)...  */
+       reply_sz = sizeof(*pfacts);
+       memset(pfacts, 0, reply_sz);
+
+       /* Request area (get_pfacts on the stack right now!) */
+       req_sz = sizeof(get_pfacts);
+       memset(&get_pfacts, 0, req_sz);
+
+       get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
+       get_pfacts.PortNumber = portnum;
+       /* Assert: All other get_pfacts fields are zero! */
+
+       dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
+                       ioc->name, portnum));
+
+       /* No non-zero fields in the get_pfacts request are greater than
+        * 1 byte in size, so we can just fire it off as is.
+        */
+       ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
+                               reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag);
+       if (ii != 0)
+               return ii;
+
+       /* Did we get a valid reply? */
+
+       /* Now byte swap the necessary fields in the response. */
+       pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
+       pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
+       pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
+       pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
+       pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
+       pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
+       pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
+       pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
+       pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendIocInit - Send IOCInit request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       IOCInit_t                ioc_init;
+       MPIDefaultReply_t        init_reply;
+       u32                      state;
+       int                      r;
+       int                      count;
+       int                      cntdn;
+
+       memset(&ioc_init, 0, sizeof(ioc_init));
+       memset(&init_reply, 0, sizeof(init_reply));
+
+       ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
+/*     ioc_init.ChainOffset = 0;                       */
+       ioc_init.Function = MPI_FUNCTION_IOC_INIT;
+/*     ioc_init.Flags = 0;                             */
+
+       /* If we are in a recovery mode and we uploaded the FW image,
+        * then this pointer is not NULL. Skip the upload a second time.
+        * Set this flag if cached_fw set for either IOC.
+        */
+       ioc->upload_fw = 0;
+       ioc_init.Flags = 0;
+       if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+               if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
+                       ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
+               else
+                       ioc->upload_fw = 1;
+       }
+       ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n",
+                  ioc->name, ioc_init.Flags, ioc->upload_fw));
+
+       if ((int)ioc->chip_type <= (int)FC929) {
+               ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
+       } else {
+               ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
+       }
+       ioc_init.MaxBuses = MPT_MAX_BUS;
+
+/*     ioc_init.MsgFlags = 0;                          */
+/*     ioc_init.MsgContext = cpu_to_le32(0x00000000);  */
+       ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);   /* in BYTES */
+
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               /* Save the upper 32-bits of the request
+                * (reply) and sense buffers.
+                */
+               ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32));
+               ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
+       } else {
+               /* Force 32-bit addressing */
+               ioc_init.HostMfaHighAddr = cpu_to_le32(0);
+               ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
+       }
+
+       dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
+                       ioc->name, &ioc_init));
+
+       r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+                               sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
+       if (r != 0)
+               return r;
+
+       /* No need to byte swap the multibyte fields in the reply
+        * since we don't even look at it's contents.
+        */
+
+       if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
+               return r;
+
+       /* YIKES!  SUPER IMPORTANT!!!
+        *  Poll IocState until _OPERATIONAL while IOC is doing
+        *  LoopInit and TargetDiscovery!
+        */
+       count = 0;
+       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60;    /* 60 seconds */
+       state = mpt_GetIocState(ioc, 1);
+       while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+               } else {
+                       mdelay(1);
+               }
+
+               if (!cntdn) {
+                       printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
+                                       ioc->name, (count+5)/HZ);
+                       return -9;
+               }
+
+               state = mpt_GetIocState(ioc, 1);
+               count++;
+       }
+       dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+                       ioc->name, count));
+
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendPortEnable - Send PortEnable request to MPT adapter port.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @portnum: Port number to enable
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     Send PortEnable to bring IOC to OPERATIONAL state.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
+{
+       PortEnable_t             port_enable;
+       MPIDefaultReply_t        reply_buf;
+       int      ii;
+       int      req_sz;
+       int      reply_sz;
+
+       /*  Destination...  */
+       reply_sz = sizeof(MPIDefaultReply_t);
+       memset(&reply_buf, 0, reply_sz);
+
+       req_sz = sizeof(PortEnable_t);
+       memset(&port_enable, 0, req_sz);
+
+       port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
+       port_enable.PortNumber = portnum;
+/*     port_enable.ChainOffset = 0;            */
+/*     port_enable.MsgFlags = 0;               */
+/*     port_enable.MsgContext = 0;             */
+
+       dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
+                       ioc->name, portnum, &port_enable));
+
+       /* RAID FW may take a long time to enable
+        */
+       if ((int)ioc->chip_type <= (int)FC929) {
+               ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+                               reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
+       } else {
+               ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+                               reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
+       }
+
+       if (ii != 0)
+               return ii;
+
+       /* We do not even look at the reply, so we need not
+        * swap the multi-byte fields.
+        */
+
+       return 0;
+}
+
+/*
+ * Inputs: size - total FW bytes
+ * Outputs: frags - number of fragments needed
+ * Return NULL if failed.
+ */
+void *
+mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
+{
+       fw_image_t      **cached_fw = NULL;
+       u8              *mem = NULL;
+       dma_addr_t      fw_dma;
+       int             alloc_total = 0;
+       int             bytes_left, bytes, num_frags;
+       int             sz, ii;
+
+       /* cached_fw
+        */
+       sz = ioc->num_fw_frags * sizeof(void *);
+       mem = kmalloc(sz, GFP_ATOMIC);
+       if (mem == NULL)
+               return NULL;
+
+       memset(mem, 0, sz);
+       cached_fw = (fw_image_t **)mem;
+       alloc_total += sz;
+
+       /* malloc fragment memory
+        * fw_image_t struct and dma for fw data
+        */
+       bytes_left = size;
+       ii = 0;
+       num_frags = 0;
+       bytes = bytes_left;
+       while((bytes_left) && (num_frags < ioc->num_fw_frags)) {
+               if (cached_fw[ii] == NULL) {
+                       mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC);
+                       if (mem == NULL)
+                               break;
+
+                       memset(mem, 0, sizeof(fw_image_t));
+                       cached_fw[ii] = (fw_image_t *)mem;
+                       alloc_total += sizeof(fw_image_t);
+               }
+
+               mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma);
+               if (mem == NULL) {
+                       if (bytes > 0x10000)
+                               bytes = 0x10000;
+                       else if (bytes > 0x8000)
+                               bytes = 0x8000;
+                       else if (bytes > 0x4000)
+                               bytes = 0x4000;
+                       else if (bytes > 0x2000)
+                               bytes = 0x2000;
+                       else if (bytes > 0x1000)
+                               bytes = 0x1000;
+                       else
+                               break;
+
+                       continue;
+               }
+
+               cached_fw[ii]->fw = mem;
+               cached_fw[ii]->fw_dma = fw_dma;
+               cached_fw[ii]->size = bytes;
+               memset(mem, 0, bytes);
+               alloc_total += bytes;
+
+               bytes_left -= bytes;
+
+               num_frags++;
+               ii++;
+       }
+
+       if (bytes_left ) {
+               /* Major Failure.
+                */
+               mpt_free_fw_memory(ioc, cached_fw);
+               return NULL;
+       }
+
+       *frags = num_frags;
+       *alloc_sz = alloc_total;
+
+       return (void *) cached_fw;
+}
+
+/*
+ * If alt_img is NULL, delete from ioc structure.
+ * Else, delete a secondary image in same format.
+ */
+void
+mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img)
+{
+       fw_image_t **cached_fw;
+       int ii;
+       int sz;
+       int alloc_freed = 0;
+
+       if (alt_img != NULL)
+               cached_fw = alt_img;
+       else
+               cached_fw = ioc->cached_fw;
+
+       if (cached_fw == NULL)
+               return;
+
+       ii = 0;
+       while ((ii < ioc->num_fw_frags) && (cached_fw[ii]!= NULL)) {
+               sz = cached_fw[ii]->size;
+               if (sz > 0) {
+                       pci_free_consistent(ioc->pcidev, sz,
+                                               cached_fw[ii]->fw, cached_fw[ii]->fw_dma);
+               }
+               cached_fw[ii]->fw = NULL;
+               alloc_freed += sz;
+
+               kfree(cached_fw[ii]);
+               cached_fw[ii] = NULL;
+               alloc_freed += sizeof(fw_image_t);
+
+               ii++;
+       }
+
+       kfree(cached_fw);
+       cached_fw = NULL;
+       sz = ioc->num_fw_frags * sizeof(void *);
+       alloc_freed += sz;
+
+       if (alt_img == NULL)
+               ioc->alloc_total -= alloc_freed;
+
+       return;
+}
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     Returns 0 for success, >0 for handshake failure
+ *             <0 for fw upload failure.
+ *
+ *     Remark: If bound IOC and a successful FWUpload was performed
+ *     on the bound IOC, the second image is discarded
+ *     and memory is free'd. Both channels must upload to prevent
+ *     IOC from running in degraded mode.
+ */
+static int
+mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       u8                       request[ioc->req_sz];
+       u8                       reply[sizeof(FWUploadReply_t)];
+       FWUpload_t              *prequest;
+       FWUploadReply_t         *preply;
+       FWUploadTCSGE_t         *ptcsge = NULL;
+       int                      sgeoffset;
+       int                      ii, sz, reply_sz;
+       int                      cmdStatus, freeMem = 0;
+       int                      num_frags, alloc_sz;
+
+       /* If the image size is 0 or if the pointer is
+        * not NULL (error), we are done.
+        */
+       if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw)
+               return 0;
+
+       ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
+       ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
+
+       ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc,
+                       ioc->facts.FWImageSize, &num_frags, &alloc_sz);
+
+       if (ioc->cached_fw == NULL) {
+               /* Major Failure.
+                */
+               mpt_free_fw_memory(ioc, NULL);
+               ioc->cached_fw = NULL;
+               
+               return -ENOMEM;
+       }
+       ioc->alloc_total += alloc_sz;
+
+       ddlprintk((KERN_INFO MYNAM ": FW Image  @ %p, sz=%d bytes\n",
+                (void *)(ulong)ioc->cached_fw, ioc->facts.FWImageSize));
+
+       prequest = (FWUpload_t *)&request;
+       preply = (FWUploadReply_t *)&reply;
+
+       /*  Destination...  */
+       memset(prequest, 0, ioc->req_sz);
+
+       reply_sz = sizeof(reply);
+       memset(preply, 0, reply_sz);
+
+       prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
+       prequest->Function = MPI_FUNCTION_FW_UPLOAD;
+       prequest->MsgContext = 0;               /* anything */
+
+       ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
+       ptcsge->Reserved = 0;
+       ptcsge->ContextSize = 0;
+       ptcsge->DetailsLength = 12;
+       ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+       ptcsge->Reserved1 = 0;
+       ptcsge->ImageOffset = 0;
+       ptcsge->ImageSize = cpu_to_le32(sz);
+
+       sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
+
+       for (ii = 0; ii < (num_frags-1); ii++) {
+               mpt_add_sge(&request[sgeoffset], MPT_SGE_FLAGS_SIMPLE_ELEMENT | 
+                       MPT_SGE_FLAGS_ADDRESSING | MPT_TRANSFER_IOC_TO_HOST |
+                       (u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma);
+
+               sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
+       }
+
+       mpt_add_sge(&request[sgeoffset],
+                       MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size,
+                       ioc->cached_fw[ii]->fw_dma);
+
+       sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
+
+       dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p) size %d \n",
+                       ioc->name, prequest, sgeoffset));
+
+       ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
+                               reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+
+       cmdStatus = -EFAULT;
+       if (ii == 0) {
+               /* Handshake transfer was complete and successful.
+                * Check the Reply Frame.
+                */
+               int status, transfer_sz;
+               status = le16_to_cpu(preply->IOCStatus);
+               if (status == MPI_IOCSTATUS_SUCCESS) {
+                       transfer_sz = le32_to_cpu(preply->ActualImageSize);
+                       if (transfer_sz == sz)
+                               cmdStatus = 0;
+               }
+       }
+       ddlprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
+                       ioc->name, cmdStatus));
+
+       /* Check to see if we have a copy of this image in
+        * host memory already.
+        */
+       if (cmdStatus == 0) {
+               ioc->upload_fw = 0;
+               if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
+                       freeMem = 1;
+       }
+
+       /* We already have a copy of this image or
+        * we had some type of an error  - either the handshake
+        * failed (i != 0) or the command did not complete successfully.
+        */
+       if (cmdStatus || freeMem) {
+
+               ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
+                       ioc->name, cmdStatus ? "incomplete" : "duplicate"));
+               mpt_free_fw_memory(ioc, NULL);
+               ioc->cached_fw = NULL;
+       }
+
+       return cmdStatus;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_downloadboot - DownloadBoot code
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @flag: Specify which part of IOC memory is to be uploaded.
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     FwDownloadBoot requires Programmed IO access.
+ *
+ *     Returns 0 for success
+ *             -1 FW Image size is 0
+ *             -2 No valid cached_fw Pointer
+ *             <0 for fw upload failure.
+ */
+static int
+mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       MpiFwHeader_t           *FwHdr = NULL;
+       MpiExtImageHeader_t     *ExtHdr;
+       fw_image_t              **pCached = NULL;
+       int                      fw_sz;
+       u32                      diag0val;
+#ifdef MPT_DEBUG
+       u32                      diag1val = 0;
+#endif
+       int                      count = 0;
+       u32                     *ptru32 = NULL;
+       u32                      diagRwData;
+       u32                      nextImage;
+       u32                      ext_offset;
+       u32                      load_addr;
+       int                      max_idx, fw_idx, ext_idx;
+       int                      left_u32s;
+
+       ddlprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
+                               ioc->name));
+#ifdef MPT_DEBUG
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+       ddlprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
+#endif
+
+       ddlprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
+                               ioc->name, ioc->facts.FWImageSize, ioc->cached_fw));
+       if (ioc->alt_ioc)
+               ddlprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
+                               ioc->name, ioc->alt_ioc->cached_fw));
+
+       /* Get dma_addr and data transfer size.
+        */
+       if ((fw_sz = ioc->facts.FWImageSize) == 0)
+               return -1;
+
+       /* Get the DMA from ioc or ioc->alt_ioc */
+       if (ioc->cached_fw != NULL)
+               pCached = (fw_image_t **)ioc->cached_fw;
+       else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL))
+               pCached = (fw_image_t **)ioc->alt_ioc->cached_fw;
+
+       ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
+                       ioc->name, pCached));
+       if (!pCached)
+               return -2;
+
+       /* Write magic sequence to WriteSequence register
+        * until enter diagnostic mode
+        */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       while ((diag0val & MPI_DIAG_DRWE) == 0) {
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+               /* wait 100 msec */
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(100 * HZ / 1000);
+#else
+                       mdelay(100);
+#endif
+               } else {
+                       mdelay (100);
+               }
+
+               count++;
+               if (count > 20) {
+                       printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+                                       ioc->name, diag0val);
+                       return -EFAULT;
+
+               }
+
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+               if (ioc->alt_ioc)
+                       diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+               ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
+#endif
+               ddlprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+                               ioc->name, diag0val));
+       }
+
+       /* Set the DiagRwEn and Disable ARM bits */
+       diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM);
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+#ifdef MPT_DEBUG
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+
+       ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+                       ioc->name, diag0val, diag1val));
+#endif
+
+       /* max_idx = 1 + maximum valid buffer index
+        */
+       max_idx = 0;
+       while (pCached[max_idx])
+               max_idx++;
+
+       fw_idx = 0;
+       FwHdr = (MpiFwHeader_t *) pCached[fw_idx]->fw;
+       ptru32 = (u32 *) FwHdr;
+       count = (FwHdr->ImageSize + 3)/4;
+       nextImage = FwHdr->NextImageHeaderOffset;
+
+       /* Write the LoadStartAddress to the DiagRw Address Register
+        * using Programmed IO
+        */
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress);
+       ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+               ioc->name, FwHdr->LoadStartAddress));
+
+       ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
+                               ioc->name, count, ptru32));
+       left_u32s = pCached[fw_idx]->size/4;
+       while (count--) {
+               if (left_u32s == 0) {
+                       fw_idx++;
+                       if (fw_idx >= max_idx) {
+                               /* FIXME
+                               ERROR CASE
+                               */
+                               ;
+                       }
+                       ptru32 = (u32 *) pCached[fw_idx]->fw;
+                       left_u32s = pCached[fw_idx]->size / 4;
+               }
+               left_u32s--;
+               CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+               ptru32++;
+       }
+
+       /* left_u32s, fw_idx and ptru32 are all valid
+        */
+       while (nextImage) {
+               ext_idx = 0;
+               ext_offset = nextImage;
+               while (ext_offset > pCached[ext_idx]->size) {
+                       ext_idx++;
+                       if (ext_idx >= max_idx) {
+                               /* FIXME
+                               ERROR CASE
+                               */
+                               ;
+                       }
+                       ext_offset -= pCached[ext_idx]->size;
+               }
+               ptru32 = (u32 *) ((char *)pCached[ext_idx]->fw + ext_offset);
+               left_u32s = pCached[ext_idx]->size - ext_offset;
+
+               if ((left_u32s * 4) >= sizeof(MpiExtImageHeader_t)) {
+                       ExtHdr = (MpiExtImageHeader_t *) ptru32;
+                       count = (ExtHdr->ImageSize + 3 )/4;
+                       nextImage = ExtHdr->NextImageHeaderOffset;
+                       load_addr = ExtHdr->LoadStartAddress;
+               } else {
+                       u32 * ptmp = (u32 *)pCached[ext_idx+1]->fw;
+
+                       switch (left_u32s) {
+                       case 5:
+                               count = *(ptru32 + 2);
+                               nextImage = *(ptru32 + 3);
+                               load_addr = *(ptru32 + 4);
+                               break;
+                       case 4:
+                               count = *(ptru32 + 2);
+                               nextImage = *(ptru32 + 3);
+                               load_addr = *ptmp;
+                               break;
+                       case 3:
+                               count = *(ptru32 + 2);
+                               nextImage = *ptmp;
+                               load_addr = *(ptmp + 1);
+                               break;
+                       case 2:
+                               count = *ptmp;
+                               nextImage = *(ptmp + 1);
+                               load_addr = *(ptmp + 2);
+                               break;
+
+                       case 1:
+                               count = *(ptmp + 1);
+                               nextImage = *(ptmp + 2);
+                               load_addr = *(ptmp + 3);
+                               break;
+
+                       default:
+                               count = 0;
+                               nextImage = 0;
+                               load_addr = 0;
+                               /* FIXME
+                               ERROR CASE
+                               */
+                               ;
+
+                       }
+                       count = (count +3)/4;
+               }
+
+               ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
+                                               ioc->name, count, ptru32));
+               CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
+
+               while (count--) {
+                       if (left_u32s == 0) {
+                               fw_idx++;
+                               if (fw_idx >= max_idx) {
+                                       /* FIXME
+                                       ERROR CASE
+                                       */
+                                       ;
+                               }
+                               ptru32 = (u32 *) pCached[fw_idx]->fw;
+                               left_u32s = pCached[fw_idx]->size / 4;
+                       }
+                       left_u32s--;
+                       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+                       ptru32++;
+               }
+       }
+
+       /* Write the IopResetVectorRegAddr */
+       ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr);
+
+       /* Write the IopResetVectorValue */
+       ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue);
+
+       /* Clear the internal flash bad bit - autoincrementing register,
+        * so must do two writes.
+        */
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+       diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
+       diagRwData |= 0x4000000;
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+       CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
+
+       /* clear the RW enable and DISARM bits */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG);
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+       /* Write 0xFF to reset the sequencer */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     KickStart - Perform hard reset of MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @force: Force hard reset
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     This routine places MPT adapter in diagnostic mode via the
+ *     WriteSequence register, and then performs a hard reset of adapter
+ *     via the Diagnostic register.
+ *
+ *     Inputs:   sleepflag - CAN_SLEEP (non-interrupt thread)
+ *                     or NO_SLEEP (interrupt thread, use mdelay)
+ *               force - 1 if doorbell active, board fault state
+ *                             board operational, IOC_RECOVERY or
+ *                             IOC_BRINGUP and there is an alt_ioc.
+ *                       0 else
+ *
+ *     Returns:
+ *              1 - hard reset, READY  
+ *              0 - no reset due to History bit, READY 
+ *             -1 - no reset due to History bit but not READY  
+ *                  OR reset but failed to come READY
+ *             -2 - no reset, could not enter DIAG mode
+ *             -3 - reset but bad FW bit
+ */
+static int
+KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
+{
+       int hard_reset_done = 0;
+       u32 ioc_state;
+       int cnt = 0;
+
+       dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+       if ((int)ioc->chip_type > (int)FC929) {
+               /* Always issue a Msg Unit Reset first. This will clear some
+                * SCSI bus hang conditions.
+                */
+               SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
+
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       schedule_timeout(HZ);
+#else
+                       mdelay(1000);
+#endif
+               } else {
+                       mdelay (1000);
+               }
+       }
+
+       hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
+       if (hard_reset_done < 0)
+               return hard_reset_done;
+
+       dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
+                       ioc->name));
+
+       for (cnt=0; cnt<HZ*20; cnt++) {
+               if ((ioc_state = mpt_GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+                       dprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
+                                       ioc->name, cnt));
+                       return hard_reset_done;
+               }
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(10);
+#endif
+               } else {
+                       mdelay (10);
+               }
+       }
+
+       printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n",
+                       ioc->name);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_diag_reset - Perform hard reset of the adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @ignore: Set if to honor and clear to ignore
+ *             the reset history bit
+ *     @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
+ *             else set to NO_SLEEP (use mdelay instead)
+ *
+ *     This routine places the adapter in diagnostic mode via the
+ *     WriteSequence register and then performs a hard reset of adapter
+ *     via the Diagnostic register. Adapter should be in ready state
+ *     upon successful completion.
+ *
+ *     Returns:  1  hard reset successful
+ *               0  no reset performed because reset history bit set
+ *              -2  enabling diagnostic mode failed
+ *              -3  diagnostic reset failed
+ */
+static int
+mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
+{
+       u32 diag0val;
+       u32 doorbell;
+       int hard_reset_done = 0;
+       int count = 0;
+#ifdef MPT_DEBUG
+       u32 diag1val = 0;
+#endif
+
+       /* Clear any existing interrupts */
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+       /* Use "Diagnostic reset" method! (only thing available!) */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+#ifdef MPT_DEBUG
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+       dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+                       ioc->name, diag0val, diag1val));
+#endif
+
+       /* Do the reset if we are told to ignore the reset history
+        * or if the reset history is 0
+        */
+       if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
+               while ((diag0val & MPI_DIAG_DRWE) == 0) {
+                       /* Write magic sequence to WriteSequence register
+                        * Loop until in diagnostic mode
+                        */
+                       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+                       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+                       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+                       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+                       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+                       CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+                       /* wait 100 msec */
+                       if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               schedule_timeout(100 * HZ / 1000);
+#else
+                               mdelay(100);
+#endif
+                       } else {
+                               mdelay (100);
+                       }
+
+                       count++;
+                       if (count > 20) {
+                               printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+                                               ioc->name, diag0val);
+                               return -2;
+
+                       }
+
+                       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+                       dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+                                       ioc->name, diag0val));
+               }
+
+#ifdef MPT_DEBUG
+               if (ioc->alt_ioc)
+                       diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+               dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+                               ioc->name, diag0val, diag1val));
+#endif
+               /* Write the PreventIocBoot bit */
+               if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
+                       diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
+                       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+               }
+
+               /*
+                * Disable the ARM (Bug fix)
+                *
+                */
+               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
+               mdelay (1);
+
+               /*
+                * Now hit the reset bit in the Diagnostic register
+                * (THE BIG HAMMER!) (Clears DRWE bit).
+                */
+               CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
+               hard_reset_done = 1;
+               dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
+                               ioc->name));
+
+               /*
+                * Call each currently registered protocol IOC reset handler
+                * with pre-reset indication.
+                * NOTE: If we're doing _IOC_BRINGUP, there can be no
+                * MptResetHandlers[] registered yet.
+                */
+               {
+                       int      ii;
+                       int      r = 0;
+
+                       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+                               if (MptResetHandlers[ii]) {
+                                       dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
+                                                       ioc->name, ii));
+                                       r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
+                                       if (ioc->alt_ioc) {
+                                               dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
+                                                               ioc->name, ioc->alt_ioc->name, ii));
+                                               r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
+                                       }
+                               }
+                       }
+                       /* FIXME?  Examine results here? */
+               }
+
+               if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
+                       /* If the DownloadBoot operation fails, the
+                        * IOC will be left unusable. This is a fatal error
+                        * case.  _diag_reset will return < 0
+                        */
+                       for (count = 0; count < 30; count ++) {
+                               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+                               if (ioc->alt_ioc)
+                                       diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+                               dprintk((MYIOC_s_INFO_FMT
+                                       "DbG2b: diag0=%08x, diag1=%08x\n",
+                                       ioc->name, diag0val, diag1val));
+#endif
+                               if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
+                                       break;
+                               }
+
+                               /* wait 1 sec */
+                               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ);
+#else
+                                       mdelay(1000);
+#endif
+                               } else {
+                                       mdelay (1000);
+                               }
+                       }
+                       if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
+                               printk(KERN_WARNING MYNAM
+                                       ": firmware downloadboot failure (%d)!\n", count);
+                       }
+
+               } else {
+                       /* Wait for FW to reload and for board
+                        * to go to the READY state.
+                        * Maximum wait is 60 seconds.
+                        * If fail, no error will check again
+                        * with calling program.
+                        */
+                       for (count = 0; count < 60; count ++) {
+                               doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+                               doorbell &= MPI_IOC_STATE_MASK;
+
+                               if (doorbell == MPI_IOC_STATE_READY) {
+                                       break;
+                               }
+
+                               /* wait 1 sec */
+                               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ);
+#else
+                                       mdelay(1000);
+#endif
+                               } else {
+                                       mdelay (1000);
+                               }
+                       }
+               }
+       }
+
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+       dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+               ioc->name, diag0val, diag1val));
+#endif
+
+       /* Clear RESET_HISTORY bit!  Place board in the
+        * diagnostic mode to update the diag register.
+        */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       count = 0;
+       while ((diag0val & MPI_DIAG_DRWE) == 0) {
+               /* Write magic sequence to WriteSequence register
+                * Loop until in diagnostic mode
+                */
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+               CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+               /* wait 100 msec */
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(100 * HZ / 1000);
+#else
+                       mdelay(100);
+#endif
+               } else {
+                       mdelay (100);
+               }
+
+               count++;
+               if (count > 20) {
+                       printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+                                       ioc->name, diag0val);
+                       break;
+               }
+               diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       }
+       diag0val &= ~MPI_DIAG_RESET_HISTORY;
+       CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       if (diag0val & MPI_DIAG_RESET_HISTORY) {
+               printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
+                               ioc->name);
+       }
+
+       /* Disable Diagnostic Mode
+        */
+       CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
+
+       /* Check FW reload status flags.
+        */
+       diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+       if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
+               printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
+                               ioc->name, diag0val);
+               return -3;
+       }
+
+#ifdef MPT_DEBUG
+       if (ioc->alt_ioc)
+               diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+       dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
+                       ioc->name, diag0val, diag1val));
+#endif
+
+       /*
+        * Reset flag that says we've enabled event notification
+        */
+       ioc->facts.EventState = 0;
+
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->facts.EventState = 0;
+
+       return hard_reset_done;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendIocReset - Send IOCReset request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reset_type: reset type, expected values are
+ *     %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
+ *
+ *     Send IOCReset request to the MPT adapter.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
+{
+       int r;
+       u32 state;
+       int cntdn, count;
+
+       dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+                       ioc->name, reset_type));
+       CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
+       if ((r = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
+               return r;
+
+       /* FW ACK'd request, wait for READY state
+        */
+       count = 0;
+       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15;    /* 15 seconds */
+
+       while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+               cntdn--;
+               count++;
+               if (!cntdn) {
+                       if (sleepFlag != CAN_SLEEP)
+                               count *= 10;
+
+                       printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+                                       ioc->name, (count+5)/HZ);
+                       return -ETIME;
+               }
+
+               if (sleepFlag == CAN_SLEEP) {
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+               } else {
+                       mdelay (1);     /* 1 msec delay */
+               }
+       }
+
+       /* TODO!
+        *  Cleanup all event stuff for this IOC; re-issue EventNotification
+        *  request if needed.
+        */
+       if (ioc->facts.Function)
+               ioc->facts.EventState = 0;
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     PrimeIocFifos - Initialize IOC request and reply FIFOs.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     This routine allocates memory for the MPT reply and request frame
+ *     pools (if necessary), and primes the IOC reply FIFO with
+ *     reply frames.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+PrimeIocFifos(MPT_ADAPTER *ioc)
+{
+       MPT_FRAME_HDR *mf;
+       unsigned long b;
+       unsigned long flags;
+       dma_addr_t aligned_mem_dma;
+       u8 *mem, *aligned_mem;
+       int i, sz;
+
+       /*  Prime reply FIFO...  */
+
+       if (ioc->reply_frames == NULL) {
+               sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+               mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma);
+               if (mem == NULL)
+                       goto out_fail;
+
+               memset(mem, 0, sz);
+               ioc->alloc_total += sz;
+               ioc->reply_alloc = mem;
+               dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%p], sz=%d bytes\n",
+                               ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, sz));
+
+               b = (unsigned long) mem;
+               b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+               aligned_mem = (u8 *) b;
+               ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
+               ioc->reply_frames_dma =
+                       (ioc->reply_alloc_dma + (aligned_mem - mem));
+
+               ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF);
+       }
+
+       /* Post Reply frames to FIFO
+        */
+       aligned_mem_dma = ioc->reply_frames_dma;
+       dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n",
+                       ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma));
+
+       for (i = 0; i < ioc->reply_depth; i++) {
+               /*  Write each address to the IOC!  */
+               CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
+               aligned_mem_dma += ioc->reply_sz;
+       }
+
+
+       /*  Request FIFO - WE manage this!  */
+
+       if (ioc->req_frames == NULL) {
+               sz = (ioc->req_sz * ioc->req_depth) + 128;
+               /*
+                *  Rounding UP to nearest 4-kB boundary here...
+                */
+               sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+
+               mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma);
+               if (mem == NULL)
+                       goto out_fail;
+
+               memset(mem, 0, sz);
+               ioc->alloc_total += sz;
+               ioc->req_alloc = mem;
+               dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%p], sz=%d bytes\n",
+                               ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, sz));
+
+               b = (unsigned long) mem;
+               b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
+               aligned_mem = (u8 *) b;
+               ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
+               ioc->req_frames_dma =
+                       (ioc->req_alloc_dma + (aligned_mem - mem));
+
+               ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF);
+
+               if (sizeof(dma_addr_t) == sizeof(u64)) {
+                       /* Check: upper 32-bits of the request and reply frame
+                        * physical addresses must be the same.
+                        */
+                       if (((u64)ioc->req_frames_dma >> 32) != ((u64)ioc->reply_frames_dma >> 32)){
+                               goto out_fail;
+                       }
+               }
+
+#if defined(CONFIG_MTRR) && 0
+               /*
+                *  Enable Write Combining MTRR for IOC's memory region.
+                *  (at least as much as we can; "size and base must be
+                *  multiples of 4 kiB"
+                */
+               ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
+                                        sz,
+                                        MTRR_TYPE_WRCOMB, 1);
+               dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
+                               ioc->name, ioc->req_alloc_dma, sz));
+#endif
+       }
+
+       /* Initialize Request frames linked list
+        */
+       aligned_mem_dma = ioc->req_frames_dma;
+       aligned_mem = (u8 *) ioc->req_frames;
+       dprintk((KERN_INFO MYNAM ": %s.req_frames   @ %p[%p]\n",
+                       ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma));
+
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+       for (i = 0; i < ioc->req_depth; i++) {
+               mf = (MPT_FRAME_HDR *) aligned_mem;
+
+               /*  Queue REQUESTs *internally*!  */
+               Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
+               aligned_mem += ioc->req_sz;
+       }
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+
+       if (ioc->sense_buf_pool == NULL) {
+               sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
+               ioc->sense_buf_pool =
+                               pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
+               if (ioc->sense_buf_pool == NULL)
+                       goto out_fail;
+
+               ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
+               ioc->alloc_total += sz;
+       }
+
+       return 0;
+
+out_fail:
+       if (ioc->reply_alloc != NULL) {
+               sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+               pci_free_consistent(ioc->pcidev,
+                               sz,
+                               ioc->reply_alloc, ioc->reply_alloc_dma);
+               ioc->reply_frames = NULL;
+               ioc->reply_alloc = NULL;
+               ioc->alloc_total -= sz;
+       }
+       if (ioc->req_alloc != NULL) {
+               sz = (ioc->req_sz * ioc->req_depth) + 128;
+               /*
+                *  Rounding UP to nearest 4-kB boundary here...
+                */
+               sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+               pci_free_consistent(ioc->pcidev,
+                               sz,
+                               ioc->req_alloc, ioc->req_alloc_dma);
+#if defined(CONFIG_MTRR) && 0
+               if (ioc->mtrr_reg > 0) {
+                       mtrr_del(ioc->mtrr_reg, 0, 0);
+                       dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n",
+                                       ioc->name));
+               }
+#endif
+               ioc->req_frames = NULL;
+               ioc->req_alloc = NULL;
+               ioc->alloc_total -= sz;
+       }
+       if (ioc->sense_buf_pool != NULL) {
+               sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
+               pci_free_consistent(ioc->pcidev,
+                               sz,
+                               ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
+               ioc->sense_buf_pool = NULL;
+       }
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_handshake_req_reply_wait - Send MPT request to and receive reply from
+ *     IOC via doorbell handshake method.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @reqBytes: Size of the request in bytes
+ *     @req: Pointer to MPT request frame
+ *     @replyBytes: Expected size of the reply in bytes
+ *     @u16reply: Pointer to area where reply should be written
+ *     @maxwait: Max wait time for a reply (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     NOTES: It is the callers responsibility to byte-swap fields in the
+ *     request which are greater than 1 byte in size.  It is also the
+ *     callers responsibility to byte-swap response fields which are
+ *     greater than 1 byte in size.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+int
+mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
+                               int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
+{
+       MPIDefaultReply_t *mptReply;
+       int failcnt = 0;
+       int t;
+
+       /*
+        * Get ready to cache a handshake reply
+        */
+       ioc->hs_reply_idx = 0;
+       mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+       mptReply->MsgLength = 0;
+
+       /*
+        * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
+        * then tell IOC that we want to handshake a request of N words.
+        * (WRITE u32val to Doorbell reg).
+        */
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       CHIPREG_WRITE32(&ioc->chip->Doorbell,
+                       ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
+                        ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
+
+       /*
+        * Wait for IOC's doorbell handshake int
+        */
+       if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
+               failcnt++;
+
+       dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n",
+                       ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+       /* Read doorbell and check for active bit */
+       if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+                       return -1;
+
+       /*
+        * Clear doorbell int (WRITE 0 to IntStatus reg),
+        * then wait for IOC to ACKnowledge that it's ready for
+        * our handshake request.
+        */
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       if (!failcnt && (t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
+               failcnt++;
+
+       if (!failcnt) {
+               int      ii;
+               u8      *req_as_bytes = (u8 *) req;
+
+               /*
+                * Stuff request words via doorbell handshake,
+                * with ACK from IOC for each.
+                */
+               for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
+                       u32 word = ((req_as_bytes[(ii*4) + 0] <<  0) |
+                                   (req_as_bytes[(ii*4) + 1] <<  8) |
+                                   (req_as_bytes[(ii*4) + 2] << 16) |
+                                   (req_as_bytes[(ii*4) + 3] << 24));
+
+                       CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
+                       if ((t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
+                               failcnt++;
+               }
+
+               dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
+               DBG_DUMP_REQUEST_FRAME_HDR(req)
+
+               dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
+                               ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
+
+               /*
+                * Wait for completion of doorbell handshake reply from the IOC
+                */
+               if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
+                       failcnt++;
+
+               /*
+                * Copy out the cached reply...
+                */
+               for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++)
+                       u16reply[ii] = ioc->hs_reply[ii];
+       } else {
+               return -99;
+       }
+
+       return -failcnt;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
+ *     in it's IntStatus register.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @howlong: How long to wait (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     This routine waits (up to ~2 seconds max) for IOC doorbell
+ *     handshake ACKnowledge.
+ *
+ *     Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
+{
+       int cntdn;
+       int count = 0;
+       u32 intstat;
+
+       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
+
+       if (sleepFlag == CAN_SLEEP) {
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+                               break;
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+                       count++;
+               }
+       } else {
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+                               break;
+                       mdelay (1);
+                       count++;
+               }
+       }
+
+       if (cntdn) {
+               dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n",
+                               ioc->name, count));
+               return count;
+       }
+
+       printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n",
+                       ioc->name, (count+5)/HZ);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
+ *     in it's IntStatus register.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @howlong: How long to wait (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
+ *
+ *     Returns a negative value on failure, else wait loop count.
+ */
+static int
+WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
+{
+       int cntdn;
+       int count = 0;
+       u32 intstat;
+
+       cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
+       if (sleepFlag == CAN_SLEEP) {
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+                               break;
+/* SAE: Can't do this in the hypervisor */
+#if XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+                       count++;
+               }
+       } else {
+               while (--cntdn) {
+                       intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+                       if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+                               break;
+                       mdelay(1);
+                       count++;
+               }
+       }
+
+       if (cntdn) {
+               dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n",
+                               ioc->name, count));
+               return count;
+       }
+
+       printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n",
+                       ioc->name, (count+5)/HZ);
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @howlong: How long to wait (in seconds)
+ *     @sleepFlag: Specifies whether the process can sleep
+ *
+ *     This routine polls the IOC for a handshake reply, 16 bits at a time.
+ *     Reply is cached to IOC private area large enough to hold a maximum
+ *     of 128 bytes of reply data.
+ *
+ *     Returns a negative value on failure, else size of reply in WORDS.
+ */
+static int
+WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
+{
+       int u16cnt = 0;
+       int failcnt = 0;
+       int t;
+       u16 *hs_reply = ioc->hs_reply;
+       volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+       u16 hword;
+
+       hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
+
+       /*
+        * Get first two u16's so we can look at IOC's intended reply MsgLength
+        */
+       u16cnt=0;
+       if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
+               failcnt++;
+       } else {
+               hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+               CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+               if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
+                       failcnt++;
+               else {
+                       hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+                       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+               }
+       }
+
+       dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n",
+                       ioc->name, le32_to_cpu(*(u32 *)hs_reply),
+                       failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+
+       /*
+        * If no error (and IOC said MsgLength is > 0), piece together
+        * reply 16 bits at a time.
+        */
+       for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
+               if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
+                       failcnt++;
+               hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+               /* don't overflow our IOC hs_reply[] buffer! */
+               if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
+                       hs_reply[u16cnt] = hword;
+               CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+       }
+
+       if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
+               failcnt++;
+       CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
+       if (failcnt) {
+               printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
+                               ioc->name);
+               return -failcnt;
+       }
+#if 0
+       else if (u16cnt != (2 * mptReply->MsgLength)) {
+               return -101;
+       }
+       else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
+               return -102;
+       }
+#endif
+
+       dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
+       DBG_DUMP_REPLY_FRAME(mptReply)
+
+       dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n",
+                       ioc->name, u16cnt/2));
+       return u16cnt/2;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetLanConfigPages - Fetch LANConfig pages.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Return: 0 for success
+ *     -ENOMEM if no memory available
+ *             -EPERM if not allowed due to ISR context
+ *             -EAGAIN if no msg frames currently available
+ *             -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       LANPage0_t              *ppage0_alloc;
+       dma_addr_t               page0_dma;
+       LANPage1_t              *ppage1_alloc;
+       dma_addr_t               page1_dma;
+       int                      rc = 0;
+       int                      data_sz;
+       int                      copy_sz;
+
+       /* Get LAN Page 0 header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = 0;
+       cfg.timeout = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength > 0) {
+               data_sz = hdr.PageLength * 4;
+               ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+               rc = -ENOMEM;
+               if (ppage0_alloc) {
+                       memset((u8 *)ppage0_alloc, 0, data_sz);
+                       cfg.physAddr = page0_dma;
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+                       if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                               /* save the data */
+                               copy_sz = MIN(sizeof(LANPage0_t), data_sz);
+                               memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
+
+                       }
+
+                       pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+
+                       /* FIXME!
+                        *      Normalize endianness of structure data,
+                        *      by byte-swapping all > 1 byte fields!
+                        */
+
+               }
+
+               if (rc)
+                       return rc;
+       }
+
+       /* Get LAN Page 1 header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 1;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength == 0)
+               return 0;
+
+       data_sz = hdr.PageLength * 4;
+       rc = -ENOMEM;
+       ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
+       if (ppage1_alloc) {
+               memset((u8 *)ppage1_alloc, 0, data_sz);
+               cfg.physAddr = page1_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                       /* save the data */
+                       copy_sz = MIN(sizeof(LANPage1_t), data_sz);
+                       memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
+               }
+
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
+
+               /* FIXME!
+                *      Normalize endianness of structure data,
+                *      by byte-swapping all > 1 byte fields!
+                */
+
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetFcPortPage0 - Fetch FCPort config Page0.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @portnum: IOC Port number
+ *
+ *     Return: 0 for success
+ *     -ENOMEM if no memory available
+ *             -EPERM if not allowed due to ISR context
+ *             -EAGAIN if no msg frames currently available
+ *             -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       FCPortPage0_t           *ppage0_alloc;
+       FCPortPage0_t           *pp0dest;
+       dma_addr_t               page0_dma;
+       int                      data_sz;
+       int                      copy_sz;
+       int                      rc;
+
+       /* Get FCPort Page 0 header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 0;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = portnum;
+       cfg.timeout = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength == 0)
+               return 0;
+
+       data_sz = hdr.PageLength * 4;
+       rc = -ENOMEM;
+       ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+       if (ppage0_alloc) {
+               memset((u8 *)ppage0_alloc, 0, data_sz);
+               cfg.physAddr = page0_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                       /* save the data */
+                       pp0dest = &ioc->fc_port_page0[portnum];
+                       copy_sz = MIN(sizeof(FCPortPage0_t), data_sz);
+                       memcpy(pp0dest, ppage0_alloc, copy_sz);
+
+                       /*
+                        *      Normalize endianness of structure data,
+                        *      by byte-swapping all > 1 byte fields!
+                        */
+                       pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
+                       pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
+                       pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
+                       pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
+                       pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
+                       pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
+                       pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
+                       pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
+                       pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
+                       pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
+                       pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
+                       pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
+                       pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
+                       pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
+                       pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
+                       pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
+
+               }
+
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     GetIoUnitPage2 - Retrieve BIOS version and boot order information.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *
+ *     Returns: 0 for success
+ *     -ENOMEM if no memory available
+ *             -EPERM if not allowed due to ISR context
+ *             -EAGAIN if no msg frames currently available
+ *             -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetIoUnitPage2(MPT_ADAPTER *ioc)
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       IOUnitPage2_t           *ppage_alloc;
+       dma_addr_t               page_dma;
+       int                      data_sz;
+       int                      rc;
+
+       /* Get the page header */
+       hdr.PageVersion = 0;
+       hdr.PageLength = 0;
+       hdr.PageNumber = 2;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
+       cfg.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.pageAddr = 0;
+       cfg.timeout = 0;
+
+       if ((rc = mpt_config(ioc, &cfg)) != 0)
+               return rc;
+
+       if (hdr.PageLength == 0)
+               return 0;
+
+       /* Read the config page */
+       data_sz = hdr.PageLength * 4;
+       rc = -ENOMEM;
+       ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
+       if (ppage_alloc) {
+               memset((u8 *)ppage_alloc, 0, data_sz);
+               cfg.physAddr = page_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               /* If Good, save data */
+               if ((rc = mpt_config(ioc, &cfg)) == 0)
+                       ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
+
+               pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
+ *     @ioc: Pointer to a Adapter Strucutre
+ *     @portnum: IOC port number
+ *
+ *     Return: -EFAULT if read of config page header fails
+ *                     or if no nvram
+ *     If read of SCSI Port Page 0 fails,
+ *             NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
+ *             Adapter settings: async, narrow
+ *             Return 1
+ *     If read of SCSI Port Page 2 fails,
+ *             Adapter settings valid
+ *             NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
+ *             Return 1
+ *     Else
+ *             Both valid
+ *             Return 0
+ *     CHECK - what type of locking mechanisms should be used????
+ */
+static int
+mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
+{
+       u8                      *pbuf = NULL;
+       dma_addr_t               buf_dma;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       int                      ii;
+       int                      data, rc = 0;
+
+       /* Allocate memory
+        */
+       if (!ioc->spi_data.nvram) {
+               int      sz;
+               u8      *mem;
+               sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
+               mem = kmalloc(sz, GFP_ATOMIC);
+               if (mem == NULL)
+                       return -EFAULT;
+
+               ioc->spi_data.nvram = (int *) mem;
+
+               dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
+                       ioc->name, ioc->spi_data.nvram, sz));
+       }
+
+       /* Invalidate NVRAM information
+        */
+       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+               ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
+       }
+
+       /* Read SPP0 header, allocate memory, then read page.
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = portnum;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;        /* use default */
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       if (header.PageLength > 0) {
+               pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+               if (pbuf) {
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                       cfg.physAddr = buf_dma;
+                       if (mpt_config(ioc, &cfg) != 0) {
+                               ioc->spi_data.maxBusWidth = MPT_NARROW;
+                               ioc->spi_data.maxSyncOffset = 0;
+                               ioc->spi_data.minSyncFactor = MPT_ASYNC;
+                               ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
+                               rc = 1;
+                       } else {
+                               /* Save the Port Page 0 data
+                                */
+                               SCSIPortPage0_t  *pPP0 = (SCSIPortPage0_t  *) pbuf;
+                               pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
+                               pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
+
+                               ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
+                               data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
+                               if (data) {
+                                       ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
+                                       data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
+                                       ioc->spi_data.minSyncFactor = (u8) (data >> 8);
+                               } else {
+                                       ioc->spi_data.maxSyncOffset = 0;
+                                       ioc->spi_data.minSyncFactor = MPT_ASYNC;
+                               }
+
+                               ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
+
+                               /* Update the minSyncFactor based on bus type.
+                                */
+                               if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
+                                       (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE))  {
+
+                                       if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
+                                               ioc->spi_data.minSyncFactor = MPT_ULTRA;
+                               }
+                       }
+                       if (pbuf) {
+                               pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+                               pbuf = NULL;
+                       }
+               }
+       }
+
+       /* SCSI Port Page 2 - Read the header then the page.
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 2;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = portnum;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+               return -EFAULT;
+
+       if (header.PageLength > 0) {
+               /* Allocate memory and read SCSI Port Page 2
+                */
+               pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+               if (pbuf) {
+                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
+                       cfg.physAddr = buf_dma;
+                       if (mpt_config(ioc, &cfg) != 0) {
+                               /* Nvram data is left with INVALID mark
+                                */
+                               rc = 1;
+                       } else {
+                               SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
+                               MpiDeviceInfo_t *pdevice = NULL;
+
+                               /* Save the Port Page 2 data
+                                * (reformat into a 32bit quantity)
+                                */
+                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                       pdevice = &pPP2->DeviceSettings[ii];
+                                       data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
+                                               (pdevice->SyncFactor << 8) | pdevice->Timeout;
+                                       ioc->spi_data.nvram[ii] = data;
+                               }
+                       }
+
+                       pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+                       pbuf = NULL;
+               }
+       }
+
+       /* Update Adapter limits with those from NVRAM
+        * Comment: Don't need to do this. Target performance
+        * parameters will never exceed the adapters limits.
+        */
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mpt_readScsiDevicePageHeaders - save version and length of SDP1
+ *     @ioc: Pointer to a Adapter Strucutre
+ *     @portnum: IOC port number
+ *
+ *     Return: -EFAULT if read of config page header fails
+ *             or 0 if success.
+ */
+static int
+mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
+{
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+
+       /* Read the SCSI Device Page 1 header
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 1;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = portnum;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
+       ioc->spi_data.sdp1length = cfg.hdr->PageLength;
+
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 0;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
+       ioc->spi_data.sdp0length = cfg.hdr->PageLength;
+
+       dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
+                       ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
+
+       dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
+                       ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
+ *     @ioc: Pointer to a Adapter Strucutre
+ *     @portnum: IOC port number
+ *
+ *     Return:
+ *     0 on success
+ *     -EFAULT if read of config page header fails or data pointer not NULL
+ *     -ENOMEM if pci_alloc failed
+ */
+static int
+mpt_findImVolumes(MPT_ADAPTER *ioc)
+{
+       IOCPage2_t              *pIoc2 = NULL;
+       ConfigPageIoc2RaidVol_t *pIocRv = NULL;
+       dma_addr_t               ioc2_dma;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       int                      jj;
+       int                      rc = 0;
+       int                      iocpage2sz;
+       u8                       nVols, nPhys;
+       u8                       vid, vbus, vioc;
+
+       if (ioc->spi_data.pIocPg3)
+               return -EFAULT; 
+
+       /* Read IOCP2 header then the page.
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 2;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+                return -EFAULT;
+
+       if (header.PageLength == 0)
+               return -EFAULT;
+
+       iocpage2sz = header.PageLength * 4;
+       pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
+       if (!pIoc2)
+               return -ENOMEM;
+
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.physAddr = ioc2_dma;
+       if (mpt_config(ioc, &cfg) != 0)
+               goto done_and_free;
+
+       /* Identify RAID Volume Id's */
+       nVols = pIoc2->NumActiveVolumes;
+       if ( nVols == 0) {
+               /* No RAID Volumes.  Done.
+                */
+       } else {
+               /* At least 1 RAID Volume
+                */
+               pIocRv = pIoc2->RaidVolume;
+               ioc->spi_data.isRaid = 0;
+               for (jj = 0; jj < nVols; jj++, pIocRv++) {
+                       vid = pIocRv->VolumeID;
+                       vbus = pIocRv->VolumeBus;
+                       vioc = pIocRv->VolumeIOC;
+
+                       /* find the match
+                        */
+                       if (vbus == 0) {
+                               ioc->spi_data.isRaid |= (1 << vid);
+                       } else {
+                               /* Error! Always bus 0
+                                */
+                       }
+               }
+       }
+
+       /* Identify Hidden Physical Disk Id's */
+       nPhys = pIoc2->NumActivePhysDisks;
+       if (nPhys == 0) {
+               /* No physical disks. Done.
+                */
+       } else {
+               mpt_read_ioc_pg_3(ioc);
+       }
+
+done_and_free:
+       if (pIoc2) {
+               pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
+               pIoc2 = NULL;
+       }
+
+       return rc;
+}
+
+int
+mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
+{
+       IOCPage3_t              *pIoc3 = NULL;
+       u8                      *mem;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       dma_addr_t               ioc3_dma;
+       int                      iocpage3sz = 0;
+
+       /* Free the old page
+        */
+       if (ioc->spi_data.pIocPg3) {
+               kfree(ioc->spi_data.pIocPg3);
+               ioc->spi_data.pIocPg3 = NULL;
+       }
+
+       /* There is at least one physical disk.
+        * Read and save IOC Page 3
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 3;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+               return 0;
+
+       if (header.PageLength == 0)
+               return 0;
+
+       /* Read Header good, alloc memory
+        */
+       iocpage3sz = header.PageLength * 4;
+       pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
+       if (!pIoc3)
+               return 0;
+
+       /* Read the Page and save the data
+        * into malloc'd memory.
+        */
+       cfg.physAddr = ioc3_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       if (mpt_config(ioc, &cfg) == 0) {
+               mem = kmalloc(iocpage3sz, GFP_ATOMIC);
+               if (mem) {
+                       memcpy(mem, (u8 *)pIoc3, iocpage3sz);
+                       ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
+               }
+       }
+
+       if (pIoc3) {
+               pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
+               pIoc3 = NULL;
+       }
+
+       return 0;
+}
+
+static void
+mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
+{
+       IOCPage1_t              *pIoc1 = NULL;
+       CONFIGPARMS              cfg;
+       ConfigPageHeader_t       header;
+       dma_addr_t               ioc1_dma;
+       int                      iocpage1sz = 0;
+       u32                      tmp;
+
+       /* Check the Coalescing Timeout in IOC Page 1
+        */
+       header.PageVersion = 0;
+       header.PageLength = 0;
+       header.PageNumber = 1;
+       header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+       cfg.hdr = &header;
+       cfg.physAddr = -1;
+       cfg.pageAddr = 0;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.dir = 0;
+       cfg.timeout = 0;
+       if (mpt_config(ioc, &cfg) != 0)
+               return;
+
+       if (header.PageLength == 0)
+               return;
+
+       /* Read Header good, alloc memory
+        */
+       iocpage1sz = header.PageLength * 4;
+       pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
+       if (!pIoc1)
+               return;
+
+       /* Read the Page and check coalescing timeout
+        */
+       cfg.physAddr = ioc1_dma;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       if (mpt_config(ioc, &cfg) == 0) {
+               
+               tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
+               if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
+                       tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
+
+                       dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
+                                       ioc->name, tmp));
+
+                       if (tmp > MPT_COALESCING_TIMEOUT) {
+                               pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
+
+                               /* Write NVRAM and current
+                                */
+                               cfg.dir = 1;
+                               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                               if (mpt_config(ioc, &cfg) == 0) {
+                                       dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
+                                                       ioc->name, MPT_COALESCING_TIMEOUT));
+
+                                       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+                                       if (mpt_config(ioc, &cfg) == 0) {
+                                               dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
+                                                               ioc->name, MPT_COALESCING_TIMEOUT));
+                                       } else {
+                                               dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
+                                                                       ioc->name));
+                                       }
+
+                               } else {
+                                       dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
+                                                               ioc->name));
+                               }
+                       }
+
+               } else {
+                       dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
+               }
+       }
+
+       if (pIoc1) {
+               pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
+               pIoc1 = NULL;
+       }
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SendEventNotification - Send EventNotification (on or off) request
+ *     to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @EvSwitch: Event switch flags
+ */
+static int
+SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
+{
+       EventNotification_t     *evnp;
+
+       evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
+       if (evnp == NULL) {
+               dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
+                               ioc->name));
+               return 0;
+       }
+       memset(evnp, 0, sizeof(*evnp));
+
+       dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+
+       evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
+       evnp->ChainOffset = 0;
+       evnp->MsgFlags = 0;
+       evnp->Switch = EvSwitch;
+
+       mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     SendEventAck - Send EventAck request to MPT adapter.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @evnp: Pointer to original EventNotification request
+ */
+static int
+SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
+{
+       EventAck_t      *pAck;
+
+       if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+               printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
+                               ioc->name);
+               return -1;
+       }
+       memset(pAck, 0, sizeof(*pAck));
+
+       dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
+
+       pAck->Function     = MPI_FUNCTION_EVENT_ACK;
+       pAck->ChainOffset  = 0;
+       pAck->MsgFlags     = 0;
+       pAck->Event        = evnp->Event;
+       pAck->EventContext = evnp->EventContext;
+
+       mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_config - Generic function to issue config message
+ *     @ioc - Pointer to an adapter structure
+ *     @cfg - Pointer to a configuration structure. Struct contains
+ *             action, page address, direction, physical address
+ *             and pointer to a configuration page header
+ *             Page header is updated.
+ *
+ *     Returns 0 for success
+ *     -EPERM if not allowed due to ISR context
+ *     -EAGAIN if no msg frames currently available
+ *     -EFAULT for non-successful reply or no reply (timeout)
+ */
+int
+mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
+{
+       Config_t        *pReq;
+       MPT_FRAME_HDR   *mf;
+       unsigned long    flags;
+       int              ii, rc;
+       int              flagsLength;
+       int              in_isr;
+
+       /* (Bugzilla:fibrebugs, #513)
+        * Bug fix (part 1)!  20010905 -sralston
+        *      Prevent calling wait_event() (below), if caller happens
+        *      to be in ISR context, because that is fatal!
+        */
+       in_isr = in_interrupt();
+       if (in_isr) {
+               dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+                               ioc->name));
+               return -EPERM;
+       }
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+               dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+                               ioc->name));
+               return -EAGAIN;
+       }
+       pReq = (Config_t *)mf;
+       pReq->Action = pCfg->action;
+       pReq->Reserved = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_CONFIG;
+       pReq->Reserved1[0] = 0;
+       pReq->Reserved1[1] = 0;
+       pReq->Reserved1[2] = 0;
+       pReq->MsgFlags = 0;
+       for (ii=0; ii < 8; ii++)
+               pReq->Reserved2[ii] = 0;
+
+       pReq->Header.PageVersion = pCfg->hdr->PageVersion;
+       pReq->Header.PageLength = pCfg->hdr->PageLength;
+       pReq->Header.PageNumber = pCfg->hdr->PageNumber;
+       pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
+       pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
+
+       /* Add a SGE to the config request.
+        */
+       if (pCfg->dir)
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
+       else
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+
+       flagsLength |= pCfg->hdr->PageLength * 4;
+
+       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
+
+       dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+               ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+
+       /* Append pCfg pointer to end of mf
+        */
+       *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) =  (void *) pCfg;
+
+       /* Initalize the timer
+        */
+       init_timer(&pCfg->timer);
+       pCfg->timer.data = (unsigned long) ioc;
+       pCfg->timer.function = mpt_timer_expired;
+       pCfg->wait_done = 0;
+
+       /* Set the timer; ensure 10 second minimum */
+       if (pCfg->timeout < 10)
+               pCfg->timer.expires = jiffies + HZ*10;
+       else
+               pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
+
+       /* Add to end of Q, set timer and then issue this command */
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM);
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+       add_timer(&pCfg->timer);
+
+       mpt_put_msg_frame(mpt_base_index, ioc->id, mf);
+/* SAE: No wait queues */
+#ifdef XENO_KILLED
+       wait_event(mpt_waitq, pCfg->wait_done);
+#else
+       /* SAE: We'll just wait a bit */
+       while(!pCfg->wait_done) {
+               mdelay(10);
+       }
+#endif
+
+       /* mf has been freed - do not access */
+
+       rc = pCfg->status;
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_timer_expired - Call back for timer process.
+ *     Used only internal config functionality.
+ *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ */
+static void
+mpt_timer_expired(unsigned long data)
+{
+       MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+
+       dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+
+       /* Perform a FW reload */
+       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+
+       /* No more processing.
+        * Hard reset clean-up will wake up
+        * process and free all resources.
+        */
+       dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_ioc_reset - Base cleanup for hard reset
+ *     @ioc: Pointer to the adapter structure
+ *     @reset_phase: Indicates pre- or post-reset functionality
+ *
+ *     Remark: Free's resources with internally generated commands.
+ */
+static int
+mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       CONFIGPARMS *pCfg;
+       unsigned long flags;
+
+       dprintk((KERN_WARNING MYNAM
+                       ": IOC %s_reset routed to MPT base driver!\n",
+                       reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+
+       if (reset_phase == MPT_IOC_SETUP_RESET) {
+               ;
+       } else if (reset_phase == MPT_IOC_PRE_RESET) {
+               /* If the internal config Q is not empty -
+                * delete timer. MF resources will be freed when
+                * the FIFO's are primed.
+                */
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
+               if (! Q_IS_EMPTY(&ioc->configQ)){
+                       pCfg = (CONFIGPARMS *)ioc->configQ.head;
+                       do {
+                               del_timer(&pCfg->timer);
+                               pCfg = (CONFIGPARMS *) (pCfg->linkage.forw);
+                       } while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+               }
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+       } else {
+               CONFIGPARMS *pNext;
+
+               /* Search the configQ for internal commands.
+                * Flush the Q, and wake up all suspended threads.
+                */
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
+               if (! Q_IS_EMPTY(&ioc->configQ)){
+                       pCfg = (CONFIGPARMS *)ioc->configQ.head;
+                       do {
+                               pNext = (CONFIGPARMS *) pCfg->linkage.forw;
+
+                               Q_DEL_ITEM(&pCfg->linkage);
+
+                               pCfg->status = MPT_CONFIG_ERROR;
+                               pCfg->wait_done = 1;
+#ifdef XENO_KILLED
+                               wake_up(&mpt_waitq);
+#else
+                               mdelay(250);
+#endif
+
+                               pCfg = pNext;
+                       } while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+               }
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+       }
+
+       return 1;               /* currently means nothing really */
+}
+
+
+#ifdef CONFIG_PROC_FS          /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_create(void)
+{
+       MPT_ADAPTER             *ioc;
+       struct proc_dir_entry   *ent;
+       int      ii;
+
+       /*
+        *      BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+        *      (single level) to multi level (e.g. "driver/message/fusion")
+        *      something here needs to change.  -sralston
+        */
+       mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
+       if (mpt_proc_root_dir == NULL)
+               return -ENOTDIR;
+
+       for (ii=0; ii < MPT_PROC_ENTRIES; ii++) {
+               ent = create_proc_entry(mpt_proc_list[ii].name,
+                               S_IFREG|S_IRUGO, mpt_proc_root_dir);
+               if (!ent) {
+                       printk(KERN_WARNING MYNAM
+                                       ": WARNING - Could not create /proc/mpt/%s entry\n",
+                                       mpt_proc_list[ii].name);
+                       continue;
+               }
+               ent->read_proc = mpt_proc_list[ii].f;
+               ent->data      = NULL;
+       }
+
+       ioc = mpt_adapter_find_first();
+       while (ioc != NULL) {
+               struct proc_dir_entry   *dent;
+               /*
+                *  Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
+                */
+               if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) {
+                       /*
+                        *  And populate it with mpt_ioc_proc_list[] entries.
+                        */
+                       for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+                               ent = create_proc_entry(mpt_ioc_proc_list[ii].name,
+                                               S_IFREG|S_IRUGO, dent);
+                               if (!ent) {
+                                       printk(KERN_WARNING MYNAM
+                                                       ": WARNING - Could not create /proc/mpt/%s/%s entry!\n",
+                                                       ioc->name,
+                                                       mpt_ioc_proc_list[ii].name);
+                                       continue;
+                               }
+                               ent->read_proc = mpt_ioc_proc_list[ii].f;
+                               ent->data      = ioc;
+                       }
+               } else {
+                       printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n",
+                                       ioc->name, mpt_ioc_proc_list[ii].name);
+               }
+               ioc = mpt_adapter_find_next(ioc);
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+static int
+procmpt_destroy(void)
+{
+       MPT_ADAPTER     *ioc;
+       int              ii;
+
+       if (!mpt_proc_root_dir)
+               return 0;
+
+       /*
+        *      BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+        *      (single level) to multi level (e.g. "driver/message/fusion")
+        *      something here needs to change.  -sralston
+        */
+
+       ioc = mpt_adapter_find_first();
+       while (ioc != NULL) {
+               char pname[32];
+               int namelen;
+
+               namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+
+               /*
+                *  Tear down each "/proc/mpt/iocN" subdirectory.
+                */
+               for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+                       (void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name);
+                       remove_proc_entry(pname, NULL);
+               }
+
+               remove_proc_entry(ioc->name, mpt_proc_root_dir);
+
+               ioc = mpt_adapter_find_next(ioc);
+       }
+
+       for (ii=0; ii < MPT_PROC_ENTRIES; ii++)
+               remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir);
+
+       if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) {
+               remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
+               mpt_proc_root_dir = NULL;
+               return 0;
+       }
+
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_summary_read - Handle read request from /proc/mpt/summary
+ *     or from /proc/mpt/iocN/summary.
+ *     @buf: Pointer to area to write information
+ *     @start: Pointer to start pointer
+ *     @offset: Offset to start writing
+ *     @request:
+ *     @eof: Pointer to EOF integer
+ *     @data: Pointer
+ *
+ *     Returns number of characters written to process performing the read.
+ */
+static int
+procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+{
+       MPT_ADAPTER *ioc;
+       char *out = buf;
+       int len;
+
+       if (data == NULL)
+               ioc = mpt_adapter_find_first();
+       else
+               ioc = data;
+
+       while (ioc) {
+               int     more = 0;
+
+               mpt_print_ioc_summary(ioc, out, &more, 0, 1);
+
+               out += more;
+               if ((out-buf) >= request) {
+                       break;
+               }
+
+               if (data == NULL)
+                       ioc = mpt_adapter_find_next(ioc);
+               else
+                       ioc = NULL;             /* force exit for iocN */
+       }
+       len = out - buf;
+
+       MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_version_read - Handle read request from /proc/mpt/version.
+ *     @buf: Pointer to area to write information
+ *     @start: Pointer to start pointer
+ *     @offset: Offset to start writing
+ *     @request:
+ *     @eof: Pointer to EOF integer
+ *     @data: Pointer
+ *
+ *     Returns number of characters written to process performing the read.
+ */
+static int
+procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+{
+       int      ii;
+       int      scsi, lan, ctl, targ, dmp;
+       char    *drvname;
+       int      len;
+
+       len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
+       len += sprintf(buf+len, "  Fusion MPT base driver\n");
+
+       scsi = lan = ctl = targ = dmp = 0;
+       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+               drvname = NULL;
+               if (MptCallbacks[ii]) {
+                       switch (MptDriverClass[ii]) {
+                       case MPTSCSIH_DRIVER:
+                               if (!scsi++) drvname = "SCSI host";
+                               break;
+                       case MPTLAN_DRIVER:
+                               if (!lan++) drvname = "LAN";
+                               break;
+                       case MPTSTM_DRIVER:
+                               if (!targ++) drvname = "SCSI target";
+                               break;
+                       case MPTCTL_DRIVER:
+                               if (!ctl++) drvname = "ioctl";
+                               break;
+                       case MPTDMP_DRIVER:
+                               if (!dmp++) drvname = "DMP";
+                               break;
+                       }
+
+                       if (drvname)
+                               len += sprintf(buf+len, "  Fusion MPT %s driver\n", drvname);
+                       /*
+                        *      Handle isense special case, because it
+                        *      doesn't do a formal mpt_register call.
+                        */
+                       if (isense_idx == ii)
+                               len += sprintf(buf+len, "  Fusion MPT isense driver\n");
+               }
+       }
+
+       MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
+ *     @buf: Pointer to area to write information
+ *     @start: Pointer to start pointer
+ *     @offset: Offset to start writing
+ *     @request:
+ *     @eof: Pointer to EOF integer
+ *     @data: Pointer
+ *
+ *     Returns number of characters written to process performing the read.
+ */
+static int
+procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+{
+       MPT_ADAPTER     *ioc = data;
+       int              len;
+       char             expVer[32];
+       int              sz;
+       int              p;
+
+       mpt_get_fw_exp_ver(expVer, ioc);
+
+       len = sprintf(buf, "%s:", ioc->name);
+       if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
+               len += sprintf(buf+len, "  (f/w download boot flag set)");
+//     if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
+//             len += sprintf(buf+len, "  CONFIG_CHECKSUM_FAIL!");
+
+       len += sprintf(buf+len, "\n  ProductID = 0x%04x (%s)\n",
+                       ioc->facts.ProductID,
+                       ioc->prod_name);
+       len += sprintf(buf+len, "  FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
+       if (ioc->facts.FWImageSize)
+               len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
+       len += sprintf(buf+len, "\n  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
+       len += sprintf(buf+len, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
+       len += sprintf(buf+len, "  EventState = 0x%02x\n", ioc->facts.EventState);
+
+       len += sprintf(buf+len, "  CurrentHostMfaHighAddr = 0x%08x\n",
+                       ioc->facts.CurrentHostMfaHighAddr);
+       len += sprintf(buf+len, "  CurrentSenseBufferHighAddr = 0x%08x\n",
+                       ioc->facts.CurrentSenseBufferHighAddr);
+
+       len += sprintf(buf+len, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
+       len += sprintf(buf+len, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+
+       len += sprintf(buf+len, "  RequestFrames @ 0x%p (Dma @ 0x%p)\n",
+                                       (void *)ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma);
+       /*
+        *  Rounding UP to nearest 4-kB boundary here...
+        */
+       sz = (ioc->req_sz * ioc->req_depth) + 128;
+       sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+       len += sprintf(buf+len, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+                                       ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+       len += sprintf(buf+len, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
+                                       4*ioc->facts.RequestFrameSize,
+                                       ioc->facts.GlobalCredits);
+
+       len += sprintf(buf+len, "  ReplyFrames   @ 0x%p (Dma @ 0x%p)\n",
+                                       (void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
+       sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+       len += sprintf(buf+len, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+                                       ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+       len += sprintf(buf+len, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
+                                       ioc->facts.CurReplyFrameSize,
+                                       ioc->facts.ReplyQueueDepth);
+
+       len += sprintf(buf+len, "  MaxDevices = %d\n",
+                       (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
+       len += sprintf(buf+len, "  MaxBuses = %d\n", ioc->facts.MaxBuses);
+
+       /* per-port info */
+       for (p=0; p < ioc->facts.NumberOfPorts; p++) {
+               len += sprintf(buf+len, "  PortNumber = %d (of %d)\n",
+                               p+1,
+                               ioc->facts.NumberOfPorts);
+               if ((int)ioc->chip_type <= (int)FC929) {
+                       if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+                               u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+                               len += sprintf(buf+len, "    LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+                                               a[5], a[4], a[3], a[2], a[1], a[0]);
+                       }
+                       len += sprintf(buf+len, "    WWN = %08X%08X:%08X%08X\n",
+                                       ioc->fc_port_page0[p].WWNN.High,
+                                       ioc->fc_port_page0[p].WWNN.Low,
+                                       ioc->fc_port_page0[p].WWPN.High,
+                                       ioc->fc_port_page0[p].WWPN.Low);
+               }
+       }
+
+       MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+}
+
+#endif         /* CONFIG_PROC_FS } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
+{
+       buf[0] ='\0';
+       if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
+               sprintf(buf, " (Exp %02d%02d)",
+                       (ioc->facts.FWVersion.Word >> 16) & 0x00FF,     /* Month */
+                       (ioc->facts.FWVersion.Word >> 8) & 0x1F);       /* Day */
+
+               /* insider hack! */
+               if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
+                       strcat(buf, " [MDBG]");
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @buffer: Pointer to buffer where IOC summary info should be written
+ *     @size: Pointer to number of bytes we wrote (set by this routine)
+ *     @len: Offset at which to start writing in buffer
+ *     @showlan: Display LAN stuff?
+ *
+ *     This routine writes (english readable) ASCII text, which represents
+ *     a summary of IOC information, to a buffer.
+ */
+void
+mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
+{
+       char expVer[32];
+       int y;
+
+       mpt_get_fw_exp_ver(expVer, ioc);
+
+       /*
+        *  Shorter summary of attached ioc's...
+        */
+       y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
+                       ioc->name,
+                       ioc->prod_name,
+                       MPT_FW_REV_MAGIC_ID_STRING,     /* "FwRev=" or somesuch */
+                       ioc->facts.FWVersion.Word,
+                       expVer,
+                       ioc->facts.NumberOfPorts,
+                       ioc->req_depth);
+
+       if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
+               u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+               y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
+                       a[5], a[4], a[3], a[2], a[1], a[0]);
+       }
+
+#ifndef __sparc__
+       y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#else
+       y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
+#endif
+
+       if (!ioc->active)
+               y += sprintf(buffer+len+y, " (disabled)");
+
+       y += sprintf(buffer+len+y, "\n");
+
+       *size = y;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     Reset Handling
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_HardResetHandler - Generic reset handler, issue SCSI Task
+ *     Management call based on input arg values.  If TaskMgmt fails,
+ *     return associated SCSI request.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Indicates if sleep or schedule must be called.
+ *
+ *     Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *     or a non-interrupt thread.  In the former, must not call schedule().
+ *
+ *     Remark: A return of -1 is a FATAL error case, as it means a
+ *     FW reload/initialization failed.
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ */
+int
+mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       int              rc;
+       unsigned long    flags;
+
+       dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+#ifdef MFCNT
+       printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
+       printk("MF count 0x%x !\n", ioc->mfcnt);
+#endif
+
+       /* Reset the adapter. Prevent more than 1 call to
+        * mpt_do_ioc_recovery at any instant in time.
+        */
+       spin_lock_irqsave(&ioc->diagLock, flags);
+       if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
+               spin_unlock_irqrestore(&ioc->diagLock, flags);
+               return 0;
+       } else {
+               ioc->diagPending = 1;
+       }
+       spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+       /* FIXME: If do_ioc_recovery fails, repeat....
+        */
+       
+       /* The SCSI driver needs to adjust timeouts on all current
+        * commands prior to the diagnostic reset being issued.
+        * Prevents timeouts occuring during a diagnostic reset...very bad.
+        * For all other protocol drivers, this is a no-op.
+        */
+       {
+               int      ii;
+               int      r = 0;
+
+               for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+                       if (MptResetHandlers[ii]) {
+                               dprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
+                                               ioc->name, ii));
+                               r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
+                               if (ioc->alt_ioc) {
+                                       dprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
+                                                       ioc->name, ioc->alt_ioc->name, ii));
+                                       r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+                               }
+                       }
+               }
+       }
+
+       if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
+               printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+                       rc, ioc->name);
+       }
+       ioc->reload_fw = 0;
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->reload_fw = 0;
+
+       spin_lock_irqsave(&ioc->diagLock, flags);
+       ioc->diagPending = 0;
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->diagPending = 0;
+       spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+       dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static char *
+EventDescriptionStr(u8 event, u32 evData0)
+{
+       char *ds = NULL;
+
+       switch(event) {
+       case MPI_EVENT_NONE:
+               ds = "None";
+               break;
+       case MPI_EVENT_LOG_DATA:
+               ds = "Log Data";
+               break;
+       case MPI_EVENT_STATE_CHANGE:
+               ds = "State Change";
+               break;
+       case MPI_EVENT_UNIT_ATTENTION:
+               ds = "Unit Attention";
+               break;
+       case MPI_EVENT_IOC_BUS_RESET:
+               ds = "IOC Bus Reset";
+               break;
+       case MPI_EVENT_EXT_BUS_RESET:
+               ds = "External Bus Reset";
+               break;
+       case MPI_EVENT_RESCAN:
+               ds = "Bus Rescan Event";
+               /* Ok, do we need to do anything here? As far as
+                  I can tell, this is when a new device gets added
+                  to the loop. */
+               break;
+       case MPI_EVENT_LINK_STATUS_CHANGE:
+               if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
+                       ds = "Link Status(FAILURE) Change";
+               else
+                       ds = "Link Status(ACTIVE) Change";
+               break;
+       case MPI_EVENT_LOOP_STATE_CHANGE:
+               if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
+                       ds = "Loop State(LIP) Change";
+               else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
+                       ds = "Loop State(LPE) Change";                  /* ??? */
+               else
+                       ds = "Loop State(LPB) Change";                  /* ??? */
+               break;
+       case MPI_EVENT_LOGOUT:
+               ds = "Logout";
+               break;
+       case MPI_EVENT_EVENT_CHANGE:
+               if (evData0)
+                       ds = "Events(ON) Change";
+               else
+                       ds = "Events(OFF) Change";
+               break;
+       case MPI_EVENT_INTEGRATED_RAID:
+               ds = "Integrated Raid";
+               break;
+       /*
+        *  MPT base "custom" events may be added here...
+        */
+       default:
+               ds = "Unknown";
+               break;
+       }
+       return ds;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     ProcessEventNotification - Route a received EventNotificationReply to
+ *     all currently regeistered event handlers.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @pEventReply: Pointer to EventNotification reply frame
+ *     @evHandlers: Pointer to integer, number of event handlers
+ *
+ *     Returns sum of event handlers return values.
+ */
+static int
+ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
+{
+       u16 evDataLen;
+       u32 evData0 = 0;
+//     u32 evCtx;
+       int ii;
+       int r = 0;
+       int handlers = 0;
+       char *evStr;
+       u8 event;
+
+       /*
+        *  Do platform normalization of values
+        */
+       event = le32_to_cpu(pEventReply->Event) & 0xFF;
+//     evCtx = le32_to_cpu(pEventReply->EventContext);
+       evDataLen = le16_to_cpu(pEventReply->EventDataLength);
+       if (evDataLen) {
+               evData0 = le32_to_cpu(pEventReply->Data[0]);
+       }
+
+       evStr = EventDescriptionStr(event, evData0);
+       dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
+                       ioc->name,
+                       evStr,
+                       event));
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
+       printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
+       for (ii = 0; ii < evDataLen; ii++)
+               printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
+       printk("\n");
+#endif
+
+       /*
+        *  Do general / base driver event processing
+        */
+       switch(event) {
+       case MPI_EVENT_NONE:                    /* 00 */
+       case MPI_EVENT_LOG_DATA:                /* 01 */
+       case MPI_EVENT_STATE_CHANGE:            /* 02 */
+       case MPI_EVENT_UNIT_ATTENTION:          /* 03 */
+       case MPI_EVENT_IOC_BUS_RESET:           /* 04 */
+       case MPI_EVENT_EXT_BUS_RESET:           /* 05 */
+       case MPI_EVENT_RESCAN:                  /* 06 */
+       case MPI_EVENT_LINK_STATUS_CHANGE:      /* 07 */
+       case MPI_EVENT_LOOP_STATE_CHANGE:       /* 08 */
+       case MPI_EVENT_LOGOUT:                  /* 09 */
+       case MPI_EVENT_INTEGRATED_RAID:         /* 0B */
+       case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:       /* 0C */
+       default:
+               break;
+       case MPI_EVENT_EVENT_CHANGE:            /* 0A */
+               if (evDataLen) {
+                       u8 evState = evData0 & 0xFF;
+
+                       /* CHECKME! What if evState unexpectedly says OFF (0)? */
+
+                       /* Update EventState field in cached IocFacts */
+                       if (ioc->facts.Function) {
+                               ioc->facts.EventState = evState;
+                       }
+               }
+               break;
+       }
+
+       /*
+        * Should this event be logged? Events are written sequentially.
+        * When buffer is full, start again at the top.
+        */
+       if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
+               int idx;
+
+               idx = ioc->eventContext % ioc->eventLogSize;
+
+               ioc->events[idx].event = event;
+               ioc->events[idx].eventContext = ioc->eventContext;
+
+               for (ii = 0; ii < 2; ii++) {
+                       if (ii < evDataLen)
+                               ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
+                       else
+                               ioc->events[idx].data[ii] =  0;
+               }
+
+               ioc->eventContext++;
+       }
+
+
+       /*
+        *  Call each currently registered protocol event handler.
+        */
+       for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+               if (MptEvHandlers[ii]) {
+                       dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+                                       ioc->name, ii));
+                       r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
+                       handlers++;
+               }
+       }
+       /* FIXME?  Examine results here? */
+
+       /*
+        *  If needed, send (a single) EventAck.
+        */
+       if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
+               if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
+                       printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+                                       ioc->name, ii);
+               }
+       }
+
+       *evHandlers = handlers;
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_fc_log_info - Log information returned from Fibre Channel IOC.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @log_info: U32 LogInfo reply word from the IOC
+ *
+ *     Refer to lsi/fc_log.h.
+ */
+static void
+mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+       static char *subcl_str[8] = {
+               "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
+               "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
+       };
+       char *desc = "unknown";
+       u8 subcl = (log_info >> 24) & 0x7;
+       u32 SubCl = log_info & 0x27000000;
+
+       switch(log_info) {
+/* FCP Initiator */
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+               desc = "Received an out of order frame - unsupported";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
+               desc = "Bad start of frame primative";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME:
+               desc = "Bad end of frame primative";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN:
+               desc = "Receiver hardware detected overrun";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER:
+               desc = "Other errors caught by IOC which require retries";
+               break;
+       case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD:
+               desc = "Main processor could not initialize sub-processor";
+               break;
+/* FC Target */
+       case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC:
+               desc = "Not sent because we are waiting for a PDISC from the initiator";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN:
+               desc = "Not sent because we are not logged in to the remote node";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP:
+               desc = "Data Out, Auto Response, not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP:
+               desc = "Data In, Auto Response, not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA:
+               desc = "Data In, Auto Response, missing data frames";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP:
+               desc = "Data Out, No Response, not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP:
+               desc = "Auto-response after a write not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP:
+               desc = "Data In, No Response, not completed due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA:
+               desc = "Data In, No Response, missing data frames";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP:
+               desc = "Manual Response not sent due to a LIP";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3:
+               desc = "Not sent because remote node does not support Class 3";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID:
+               desc = "Not sent because login to remote node not validated";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
+               desc = "Cleared from the outbound queue after a logout";
+               break;
+       case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
+               desc = "Cleared waiting for data after a logout";
+               break;
+/* LAN */
+       case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING:
+               desc = "Transaction Context Sgl Missing";
+               break;
+       case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE:
+               desc = "Transaction Context found before an EOB";
+               break;
+       case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET:
+               desc = "Transaction Context value has reserved bits set";
+               break;
+       case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG:
+               desc = "Invalid SGL Flags";
+               break;
+/* FC Link */
+       case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT:
+               desc = "Loop initialization timed out";
+               break;
+       case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED:
+               desc = "Another system controller already initialized the loop";
+               break;
+       case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
+               desc = "Not synchronized to signal or still negotiating (possible cable problem)";
+               break;
+       case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR:
+               desc = "CRC check detected error on received frame";
+               break;
+       }
+
+       printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}",
+                       ioc->name, log_info, subcl_str[subcl]);
+       if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
+               printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
+       else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE)
+               printk("\n");           /* StateChg in LogInfo & 0x00FFFFFF, above */
+       else
+               printk("\n" KERN_INFO " %s\n", desc);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mr: Pointer to MPT reply frame
+ *     @log_info: U32 LogInfo word from the IOC
+ *
+ *     Refer to lsi/sp_log.h.
+ */
+static void
+mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
+{
+       u32 info = log_info & 0x00FF0000;
+       char *desc = "unknown";
+
+       switch (info) {
+       case 0x00010000:
+               desc = "bug! MID not found";
+               if (ioc->reload_fw == 0)
+                       ioc->reload_fw++;
+               break;
+
+       case 0x00020000:
+               desc = "Parity Error";
+               break;
+
+       case 0x00030000:
+               desc = "ASYNC Outbound Overrun";
+               break;
+
+       case 0x00040000:
+               desc = "SYNC Offset Error";
+               break;
+
+       case 0x00050000:
+               desc = "BM Change";
+               break;
+
+       case 0x00060000:
+               desc = "Msg In Overflow";
+               break;
+
+       case 0x00070000:
+               desc = "DMA Error";
+               break;
+
+       case 0x00080000:
+               desc = "Outbound DMA Overrun";
+               break;
+       }
+
+       printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI
+ *     OpCode strings from the (optional) isense module.
+ *     @ascqTable: Pointer to ASCQ_Table_t structure
+ *     @ascqtbl_sz: Number of entries in ASCQ_Table
+ *     @opsTable: Pointer to array of SCSI OpCode strings (char pointers)
+ *
+ *     Specialized driver registration routine for the isense driver.
+ */
+int
+mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable)
+{
+       int r = 0;
+
+       if (ascqTable && ascqtbl_sz && opsTable) {
+               mpt_v_ASCQ_TablePtr = ascqTable;
+               mpt_ASCQ_TableSz = ascqtbl_sz;
+               mpt_ScsiOpcodesPtr = opsTable;
+               printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+               isense_idx = last_drv_idx;
+               r = 1;
+       }
+       mpt_inc_use_count();
+       return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI
+ *     OpCode strings from the isense driver.
+ *
+ *     Specialized driver deregistration routine for the isense driver.
+ */
+void
+mpt_deregister_ascqops_strings(void)
+{
+       mpt_v_ASCQ_TablePtr = NULL;
+       mpt_ASCQ_TableSz = 0;
+       mpt_ScsiOpcodesPtr = NULL;
+       printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+       isense_idx = -1;
+       mpt_dec_use_count();
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+EXPORT_SYMBOL(mpt_adapters);
+EXPORT_SYMBOL(mpt_proc_root_dir);
+EXPORT_SYMBOL(DmpService);
+EXPORT_SYMBOL(mpt_register);
+EXPORT_SYMBOL(mpt_deregister);
+EXPORT_SYMBOL(mpt_event_register);
+EXPORT_SYMBOL(mpt_event_deregister);
+EXPORT_SYMBOL(mpt_reset_register);
+EXPORT_SYMBOL(mpt_reset_deregister);
+EXPORT_SYMBOL(mpt_get_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_free_msg_frame);
+EXPORT_SYMBOL(mpt_add_sge);
+EXPORT_SYMBOL(mpt_add_chain);
+EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_handshake_req_reply_wait);
+EXPORT_SYMBOL(mpt_adapter_find_first);
+EXPORT_SYMBOL(mpt_adapter_find_next);
+EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_GetIocState);
+EXPORT_SYMBOL(mpt_print_ioc_summary);
+EXPORT_SYMBOL(mpt_lan_index);
+EXPORT_SYMBOL(mpt_stm_index);
+EXPORT_SYMBOL(mpt_HardResetHandler);
+EXPORT_SYMBOL(mpt_config);
+EXPORT_SYMBOL(mpt_read_ioc_pg_3);
+EXPORT_SYMBOL(mpt_alloc_fw_memory);
+EXPORT_SYMBOL(mpt_free_fw_memory);
+
+EXPORT_SYMBOL(mpt_register_ascqops_strings);
+EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
+EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr);
+EXPORT_SYMBOL(mpt_ASCQ_TableSz);
+EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     fusion_init - Fusion MPT base driver initialization routine.
+ *
+ *     Returns 0 for success, non-zero for failure.
+ */
+int __init
+fusion_init(void)
+{
+       int i;
+
+       if (FusionInitCalled++) {
+               dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n"));
+               return 0;
+       }
+
+       Q_INIT(&MptAdapters, MPT_ADAPTER);                      /* set to empty */
+       for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
+               MptCallbacks[i] = NULL;
+               MptDriverClass[i] = MPTUNKNOWN_DRIVER;
+               MptEvHandlers[i] = NULL;
+               MptResetHandlers[i] = NULL;
+       }
+
+       DmpService = NULL;
+
+       /* NEW!  20010120 -sralston
+        *  Register ourselves (mptbase) in order to facilitate
+        *  EventNotification handling.
+        */
+       mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+
+       /* Register for hard reset handling callbacks.
+        */
+       if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
+               dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
+       } else {
+               /* FIXME! */
+       }
+
+       if ((i = mpt_pci_scan()) < 0)
+               return i;
+
+       show_mptmod_ver(my_NAME, my_VERSION);
+       printk(KERN_INFO COPYRIGHT "\n");
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     fusion_exit - Perform driver unload cleanup.
+ *
+ *     This routine frees all resources associated with each MPT adapter
+ *     and removes all %MPT_PROCFS_MPTBASEDIR entries.
+ */
+static void
+fusion_exit(void)
+{
+       MPT_ADAPTER *this;
+       struct pci_dev *pdev = NULL;
+
+       dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
+
+       /* Whups?  20010120 -sralston
+        *  Moved this *above* removal of all MptAdapters!
+        */
+#ifdef CONFIG_PROC_FS
+       (void) procmpt_destroy();
+#endif
+
+       while (! Q_IS_EMPTY(&MptAdapters)) {
+               this = MptAdapters.head;
+
+               /* Disable interrupts! */
+               CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+
+               this->active = 0;
+
+               pdev = (struct pci_dev *)this->pcidev;
+               mptscsih_sync_irq(pdev->irq);
+
+               /* Clear any lingering interrupt */
+               CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+
+               CHIPREG_READ32(&this->chip->IntStatus);
+
+               Q_DEL_ITEM(this);
+               mpt_adapter_dispose(this);
+       }
+
+       mpt_reset_deregister(mpt_base_index);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+module_init(fusion_init);
+module_exit(fusion_exit);
diff --git a/xen/drivers/message/fusion/mptbase.h b/xen/drivers/message/fusion/mptbase.h
new file mode 100644 (file)
index 0000000..02e6e4d
--- /dev/null
@@ -0,0 +1,1123 @@
+/*
+ *  linux/drivers/message/fusion/mptbase.h
+ *      High performance SCSI + LAN / Fibre Channel device drivers.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *     (see mptbase.c)
+ *
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:lstephens@lsil.com)
+ *
+ *  $Id: mptbase.h,v 1.149 2003/05/07 14:08:31 pdelaney Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef MPTBASE_H_INCLUDED
+#define MPTBASE_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <xeno/timer.h>
+
+#include "linux_compat.h"      /* linux-2.2.x (vs. -2.4.x) tweaks */
+#include "scsi3.h"             /* SCSI defines */
+
+#include "lsi/mpi_type.h"
+#include "lsi/mpi.h"           /* Fusion MPI(nterface) basic defs */
+#include "lsi/mpi_ioc.h"       /* Fusion MPT IOC(ontroller) defs */
+#include "lsi/mpi_cnfg.h"      /* IOC configuration support */
+#include "lsi/mpi_init.h"      /* SCSI Host (initiator) protocol support */
+#include "lsi/mpi_lan.h"       /* LAN over FC protocol support */
+#include "lsi/mpi_raid.h"      /* Integrated Mirroring support */
+
+#include "lsi/mpi_fc.h"                /* Fibre Channel (lowlevel) support */
+#include "lsi/mpi_targ.h"      /* SCSI/FCP Target protcol support */
+#include "lsi/fc_log.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef MODULEAUTHOR
+#define MODULEAUTHOR   "LSI Logic Corporation"
+#endif
+
+#ifndef COPYRIGHT
+#define COPYRIGHT      "Copyright (c) 1999-2002 " MODULEAUTHOR
+#endif
+
+#define MPT_LINUX_VERSION_COMMON       "2.05.05+"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-2.05.05+"
+#define WHAT_MAGIC_STRING              "@" "(" "#" ")"
+
+#define show_mptmod_ver(s,ver)  \
+       printk(KERN_INFO "%s %s\n", s, ver);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Fusion MPT(linux) driver configurable stuff...
+ */
+#define MPT_MAX_ADAPTERS               18
+#define MPT_MAX_PROTOCOL_DRIVERS       16
+#define MPT_MAX_BUS                    1       /* Do not change */
+#define MPT_MAX_FC_DEVICES             255
+#define MPT_MAX_SCSI_DEVICES           16
+#define MPT_LAST_LUN                   31
+#define MPT_SENSE_BUFFER_ALLOC         64
+       /* allow for 256 max sense alloc, but only 255 max request */
+#if MPT_SENSE_BUFFER_ALLOC >= 256
+#      undef MPT_SENSE_BUFFER_ALLOC
+#      define MPT_SENSE_BUFFER_ALLOC   256
+#      define MPT_SENSE_BUFFER_SIZE    255
+#else
+#      define MPT_SENSE_BUFFER_SIZE    MPT_SENSE_BUFFER_ALLOC
+#endif
+
+#define MPT_NAME_LENGTH                        32
+
+#define MPT_PROCFS_MPTBASEDIR          "mpt"
+                                               /* chg it to "driver/fusion" ? */
+#define MPT_PROCFS_SUMMARY_ALL_NODE            MPT_PROCFS_MPTBASEDIR "/summary"
+#define MPT_PROCFS_SUMMARY_ALL_PATHNAME                "/proc/" MPT_PROCFS_SUMMARY_ALL_NODE
+#define MPT_FW_REV_MAGIC_ID_STRING             "FwRev="
+
+#define  MPT_MAX_REQ_DEPTH             1023
+#define  MPT_DEFAULT_REQ_DEPTH         256
+#define  MPT_MIN_REQ_DEPTH             128
+
+#define  MPT_MAX_REPLY_DEPTH           MPT_MAX_REQ_DEPTH
+#define  MPT_DEFAULT_REPLY_DEPTH       128
+#define  MPT_MIN_REPLY_DEPTH           8
+#define  MPT_MAX_REPLIES_PER_ISR       32
+
+#define  MPT_MAX_FRAME_SIZE            128
+#define  MPT_DEFAULT_FRAME_SIZE                128
+
+#define  MPT_SG_REQ_128_SCALE          1
+#define  MPT_SG_REQ_96_SCALE           2
+#define  MPT_SG_REQ_64_SCALE           4
+
+#define         CAN_SLEEP                      1
+#define  NO_SLEEP                      0
+
+#define MPT_COALESCING_TIMEOUT         0x10
+
+/*
+ * SCSI transfer rate defines.
+ */
+#define MPT_ULTRA320                   0x08
+#define MPT_ULTRA160                   0x09
+#define MPT_ULTRA2                     0x0A
+#define MPT_ULTRA                      0x0C
+#define MPT_FAST                       0x19
+#define MPT_SCSI                       0x32
+#define MPT_ASYNC                      0xFF
+
+#define MPT_NARROW                     0
+#define MPT_WIDE                       1
+
+#ifdef __KERNEL__      /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* SAE: Xen doesn't have a proc filesystem */
+#if defined(CONFIG_PROC_FS)
+#include <linux/proc_fs.h>
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Attempt semi-consistent error & warning msgs across
+ * MPT drivers.  NOTE: Users of these macro defs must
+ * themselves define their own MYNAM.
+ */
+#define MYIOC_s_INFO_FMT               KERN_INFO MYNAM ": %s: "
+#define MYIOC_s_NOTE_FMT               KERN_NOTICE MYNAM ": %s: "
+#define MYIOC_s_WARN_FMT               KERN_WARNING MYNAM ": %s: WARNING - "
+#define MYIOC_s_ERR_FMT                        KERN_ERR MYNAM ": %s: ERROR - "
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  MPT protocol driver defs...
+ */
+typedef enum {
+       MPTBASE_DRIVER,         /* MPT base class */
+       MPTCTL_DRIVER,          /* MPT ioctl class */
+       MPTSCSIH_DRIVER,        /* MPT SCSI host (initiator) class */
+       MPTLAN_DRIVER,          /* MPT LAN class */
+       MPTSTM_DRIVER,          /* MPT SCSI target mode class */
+       MPTDMP_DRIVER,          /* MPT Dynamic Multi-pathing class */
+       MPTUNKNOWN_DRIVER
+} MPT_DRIVER_CLASS;
+
+/*
+ *  MPT adapter / port / bus / device info structures...
+ */
+
+typedef union _MPT_FRAME_TRACKER {
+       struct {
+               struct _MPT_FRAME_HDR   *forw;
+               struct _MPT_FRAME_HDR   *back;
+               u32                      arg1;
+               u32                      pad;
+               void                    *argp1;
+#ifndef MPT_SCSI_USE_NEW_EH
+               void                    *argp2;
+#endif
+       } linkage;
+       /*
+        * NOTE: When request frames are free, on the linkage structure
+        * contets are valid.  All other values are invalid.
+        * In particular, do NOT reply on offset [2]
+        * (in words) being the * message context.
+        * The message context must be reset (computed via base address
+        * + an offset) prior to issuing any command.
+        *
+        * NOTE2: On non-32-bit systems, where pointers are LARGE,
+        * using the linkage pointers destroys our sacred MsgContext
+        * field contents.  But we don't care anymore because these
+        * are now reset in mpt_put_msg_frame() just prior to sending
+        * a request off to the IOC.
+        */
+       struct {
+               u32 __hdr[2];
+               /*
+                * The following _MUST_ match the location of the
+                * MsgContext field in the MPT message headers.
+                */
+               union {
+                       u32              MsgContext;
+                       struct {
+                               u16      req_idx;       /* Request index */
+                               u8       cb_idx;        /* callback function index */
+                               u8       rsvd;
+                       } fld;
+               } msgctxu;
+       } hwhdr;
+       /*
+        * Remark: 32 bit identifier:
+        *  31-24: reserved
+        *  23-16: call back index
+        *  15-0 : request index
+        */
+} MPT_FRAME_TRACKER;
+
+/*
+ *  We might want to view/access a frame as:
+ *    1) generic request header
+ *    2) SCSIIORequest
+ *    3) SCSIIOReply
+ *    4) MPIDefaultReply
+ *    5) frame tracker
+ */
+typedef struct _MPT_FRAME_HDR {
+       union {
+               MPIHeader_t             hdr;
+               SCSIIORequest_t         scsireq;
+               SCSIIOReply_t           sreply;
+               MPIDefaultReply_t       reply;
+               MPT_FRAME_TRACKER       frame;
+       } u;
+} MPT_FRAME_HDR;
+
+#define MPT_REQ_MSGFLAGS_DROPME                0x80
+
+/* Used for tracking the free request frames
+ * and free reply frames.
+ */
+typedef struct _MPT_Q_TRACKER {
+       MPT_FRAME_HDR   *head;
+       MPT_FRAME_HDR   *tail;
+} MPT_Q_TRACKER;
+
+
+typedef struct _MPT_SGL_HDR {
+       SGESimple32_t    sge[1];
+} MPT_SGL_HDR;
+
+typedef struct _MPT_SGL64_HDR {
+       SGESimple64_t    sge[1];
+} MPT_SGL64_HDR;
+
+
+typedef struct _Q_ITEM {
+       struct _Q_ITEM  *forw;
+       struct _Q_ITEM  *back;
+} Q_ITEM;
+
+typedef struct _Q_TRACKER {
+       struct _Q_ITEM  *head;
+       struct _Q_ITEM  *tail;
+} Q_TRACKER;
+
+typedef struct _MPT_DONE_Q {
+       struct _MPT_DONE_Q      *forw;
+       struct _MPT_DONE_Q      *back;
+       void                    *argp;
+} MPT_DONE_Q;
+
+typedef struct _DONE_Q_TRACKER {
+       MPT_DONE_Q      *head;
+       MPT_DONE_Q      *tail;
+} DONE_Q_TRACKER;
+
+/*
+ *  Chip-specific stuff... FC929 delineates break between
+ *  FC and Parallel SCSI parts. Do NOT re-order.
+ */
+
+typedef enum {
+       FC919X = 0x0819,
+       FC929X = 0x0829,
+       FC909 = 0x0909,
+       FC919 = 0x0919,
+       FC929 = 0x0929,
+       C1030 = 0x1030,
+       C1035 = 0x1035,
+       FCUNK = 0xFBAD
+} CHIP_TYPE;
+
+/*
+ *  System interface register set
+ */
+
+typedef struct _SYSIF_REGS
+{
+       u32     Doorbell;       /* 00     System<->IOC Doorbell reg  */
+       u32     WriteSequence;  /* 04     Write Sequence register    */
+       u32     Diagnostic;     /* 08     Diagnostic register        */
+       u32     TestBase;       /* 0C     Test Base Address          */
+       u32     DiagRwData;     /* 10     Read Write Data (fw download)   */
+       u32     DiagRwAddress;  /* 14     Read Write Address (fw download)*/
+       u32     Reserved1[6];   /* 18-2F  reserved for future use    */
+       u32     IntStatus;      /* 30     Interrupt Status           */
+       u32     IntMask;        /* 34     Interrupt Mask             */
+       u32     Reserved2[2];   /* 38-3F  reserved for future use    */
+       u32     RequestFifo;    /* 40     Request Post/Free FIFO     */
+       u32     ReplyFifo;      /* 44     Reply   Post/Free FIFO     */
+       u32     Reserved3[2];   /* 48-4F  reserved for future use    */
+       u32     HostIndex;      /* 50     Host Index register        */
+       u32     Reserved4[15];  /* 54-8F                             */
+       u32     Fubar;          /* 90     For Fubar usage            */
+       u32     Reserved5[27];  /* 94-FF                             */
+} SYSIF_REGS;
+
+/*
+ * NOTE: Use MPI_{DOORBELL,WRITESEQ,DIAG}_xxx defs in lsi/mpi.h
+ * in conjunction with SYSIF_REGS accesses!
+ */
+
+
+/*
+ *     Dynamic Multi-Pathing specific stuff...
+ */
+#define DMP_MAX_PATHS  8
+
+typedef struct _PathInfo {
+       u8               ioc;
+       u8               target;
+       u8               pad;
+       u8               pflags;
+} PathInfo;
+
+#define PATHINFO_FLAGS_OWNED           0x01
+#define PATHINFO_FLAGS_EXISTS          0x02
+#define PATHINFO_FLAGS_AVAILABLE       0x04
+#define PATHINFO_FLAGS_SECONDARY       0x08
+
+#define PFLAGS_EXISTS_AND_AVAIL                (PATHINFO_FLAGS_EXISTS|PATHINFO_FLAGS_AVAILABLE)
+#define PFLAGS_AVAIL_AND_OWNED         (PATHINFO_FLAGS_AVAILABLE|PATHINFO_FLAGS_OWNED)
+
+typedef struct _ScsiCmndTracker {
+       void                    *head;
+       void                    *tail;
+} ScsiCmndTracker;
+
+
+/*
+ *     VirtDevice - FC LUN device or SCSI target device
+ *     (used to be FCSCSI_TARGET)
+ */
+typedef struct _VirtDevice {
+       struct _VirtDevice      *forw;
+       struct _VirtDevice      *back;
+       struct scsi_device      *device;
+       rwlock_t                 VdevLock;
+       int                      ref_cnt;
+       u8                       tflags;
+       u8                       ioc_id;
+       u8                       target_id;
+       u8                       bus_id;
+       u8                       minSyncFactor; /* 0xFF is async */
+       u8                       maxOffset;     /* 0 if async */
+       u8                       maxWidth;      /* 0 if narrow, 1 if wide*/
+       u8                       negoFlags;     /* bit field, 0 if WDTR/SDTR/QAS allowed */
+       u8                       raidVolume;    /* set, if RAID Volume */
+       u8                       type;          /* byte 0 of Inquiry data */
+       u8                       cflags;        /* controller flags */
+       u8                       rsvd1raid;
+       int                      npaths;
+       u16                      fc_phys_lun;
+       u16                      fc_xlat_lun;
+       int                      stall_detected;
+       PathInfo                 path[DMP_MAX_PATHS];
+       struct timer_list        stall_timer;
+       struct timer_list        retry_timer;
+       struct timer_list        gone_timer;
+       ScsiCmndTracker          WaitQ;
+       ScsiCmndTracker          SentQ;
+       ScsiCmndTracker          DoneQ;
+       u32                      num_luns;
+//--- LUN split here?
+       u32                      luns;          /* Max LUNs is 32 */
+       u8                       inq_data[SCSI_STD_INQUIRY_BYTES];      /* 36 */
+       u8                       pad0[4];
+       u8                       inq00_data[20];
+       u8                       pad1[4];
+               /* IEEE Registered Extended Identifier
+                  obtained via INQUIRY VPD page 0x83 */
+               /* NOTE: Do not separate uniq_prepad and uniq_data
+                  as they are treateed as a single entity in the code */
+       u8                       uniq_prepad[8];
+       u8                       uniq_data[20];
+       u8                       pad2[4];
+       u8                       inqC3_data[12];
+       u8                       pad3[4];
+       u8                       inqC9_data[12];
+       u8                       pad4[4];
+       u8                       dev_vol_name[64];
+} VirtDevice;
+
+/*
+ *  Fibre Channel (SCSI) target device and associated defines...
+ */
+#define MPT_TARGET_DEFAULT_DV_STATUS   0
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,55)
+#define MPT_TARGET_FLAGS_CONFIGURED    0x02
+#define MPT_TARGET_FLAGS_Q_YES         0x08
+#else
+#define MPT_TARGET_FLAGS_VALID_NEGO    0x01
+#define MPT_TARGET_FLAGS_VALID_INQUIRY 0x02
+#define MPT_TARGET_FLAGS_Q_YES         0x08
+#define MPT_TARGET_FLAGS_VALID_56      0x10
+#endif
+
+#define MPT_TARGET_NO_NEGO_WIDE                0x01
+#define MPT_TARGET_NO_NEGO_SYNC                0x02
+#define MPT_TARGET_NO_NEGO_QAS         0x04
+
+typedef struct _VirtDevTracker {
+       struct _VirtDevice      *head;
+       struct _VirtDevice      *tail;
+       rwlock_t                 VlistLock;
+       int                      pad;
+} VirtDevTracker;
+
+/* SAE: Xen doesn't have proc */
+#if defined(CONFIG_PROC_FS)
+
+/*
+ *     /proc/mpt interface
+ */
+typedef struct {
+       const char      *name;
+       mode_t           mode;
+       int              pad;
+       read_proc_t     *read_proc;
+       write_proc_t    *write_proc;
+} mpt_proc_entry_t;
+
+#define MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len) \
+do { \
+       len -= offset;                  \
+       if (len < request) {            \
+               *eof = 1;               \
+               if (len <= 0)           \
+                       return 0;       \
+       } else                          \
+               len = request;          \
+       *start = buf + offset;          \
+       return len;                     \
+} while (0)
+
+#endif
+
+/*
+ *     IOCTL structure and associated defines
+ */
+
+#define MPT_IOCTL_STATUS_DID_IOCRESET  0x01    /* IOC Reset occurred on the current*/
+#define MPT_IOCTL_STATUS_RF_VALID      0x02    /* The Reply Frame is VALID */
+#define MPT_IOCTL_STATUS_TIMER_ACTIVE  0x04    /* The timer is running */
+#define MPT_IOCTL_STATUS_SENSE_VALID   0x08    /* Sense data is valid */
+#define MPT_IOCTL_STATUS_COMMAND_GOOD  0x10    /* Command Status GOOD */
+#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE        0x20    /* The TM timer is running */
+#define MPT_IOCTL_STATUS_TM_FAILED     0x40    /* User TM request failed */
+
+#define MPTCTL_RESET_OK                        0x01    /* Issue Bus Reset */
+
+typedef struct _MPT_IOCTL {
+       struct _MPT_ADAPTER     *ioc;
+       struct timer_list        timer;         /* timer function for this adapter */
+       u8                       ReplyFrame[MPT_DEFAULT_FRAME_SIZE];    /* reply frame data */
+       u8                       sense[MPT_SENSE_BUFFER_ALLOC];
+       int                      wait_done;     /* wake-up value for this ioc */
+       u8                       rsvd;
+       u8                       status;        /* current command status */
+       u8                       reset;         /* 1 if bus reset allowed */
+       u8                       target;        /* target for reset */
+       void                    *tmPtr;
+       struct timer_list        TMtimer;       /* timer function for this adapter */
+} MPT_IOCTL;
+
+/*
+ *  Event Structure and define
+ */
+#define MPTCTL_EVENT_LOG_SIZE          (0x0000000A)
+typedef struct _mpt_ioctl_events {
+       u32     event;          /* Specified by define above */
+       u32     eventContext;   /* Index or counter */
+       int     data[2];        /* First 8 bytes of Event Data */
+} MPT_IOCTL_EVENTS;
+
+/*
+ * CONFIGPARM status  defines
+ */
+#define MPT_CONFIG_GOOD                MPI_IOCSTATUS_SUCCESS
+#define MPT_CONFIG_ERROR       0x002F
+
+/*
+ *     Substructure to store SCSI specific configuration page data
+ */
+                                               /* dvStatus defines: */
+#define MPT_SCSICFG_NEGOTIATE          0x01    /* Negotiate on next IO */
+#define MPT_SCSICFG_NEED_DV            0x02    /* Schedule DV */
+#define MPT_SCSICFG_DV_PENDING         0x04    /* DV on this physical id pending */
+#define MPT_SCSICFG_DV_NOT_DONE                0x08    /* DV has not been performed */
+#define MPT_SCSICFG_BLK_NEGO           0x10    /* WriteSDP1 with WDTR and SDTR disabled */
+#define MPT_SCSICFG_RELOAD_IOC_PG3     0x20    /* IOC Pg 3 data is obsolete */
+                                               /* Args passed to writeSDP1: */
+#define MPT_SCSICFG_USE_NVRAM          0x01    /* WriteSDP1 using NVRAM */
+#define MPT_SCSICFG_ALL_IDS            0x02    /* WriteSDP1 to all IDS */
+/* #define MPT_SCSICFG_BLK_NEGO                0x10       WriteSDP1 with WDTR and SDTR disabled */
+
+typedef        struct _ScsiCfgData {
+       int             *nvram;                 /* table of device NVRAM values */
+       IOCPage3_t      *pIocPg3;               /* table of physical disks */
+       u8               dvStatus[MPT_MAX_SCSI_DEVICES];
+       int              isRaid;                /* bit field, 1 if RAID */
+       u8               minSyncFactor;         /* 0xFF if async */
+       u8               maxSyncOffset;         /* 0 if async */
+       u8               maxBusWidth;           /* 0 if narrow, 1 if wide */
+       u8               busType;               /* SE, LVD, HD */
+       u8               sdp1version;           /* SDP1 version */
+       u8               sdp1length;            /* SDP1 length  */
+       u8               sdp0version;           /* SDP0 version */
+       u8               sdp0length;            /* SDP0 length  */
+       u8               dvScheduled;           /* 1 if scheduled */
+       u8               forceDv;               /* 1 to force DV scheduling */
+       u8               noQas;                 /* Disable QAS for this adapter */
+       u8               rsvd[2];
+} ScsiCfgData;
+
+typedef struct _fw_image {
+       char            *fw;
+       dma_addr_t       fw_dma;
+       u32              size;
+       u32              rsvd;
+} fw_image_t;
+
+/*
+ *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
+ */
+typedef struct _MPT_ADAPTER
+{
+       struct _MPT_ADAPTER     *forw;
+       struct _MPT_ADAPTER     *back;
+       int                      id;            /* Unique adapter id N {0,1,2,...} */
+       int                      pci_irq;       /* This irq           */
+       char                     name[MPT_NAME_LENGTH]; /* "iocN"             */
+       char                    *prod_name;     /* "LSIFC9x9"         */
+       volatile SYSIF_REGS     *chip;          /* == c8817000 (mmap) */
+       volatile SYSIF_REGS     *pio_chip;      /* Programmed IO (downloadboot) */
+       u32                      mem_phys;      /* == f4020000 (mmap) */
+       u32                      pio_mem_phys;  /* Programmed IO (downloadboot) */
+       int                      mem_size;      /* mmap memory size */
+       int                      alloc_total;
+       u32                      last_state;
+       int                      active;
+       u8                      *reply_alloc;   /* Reply frames alloc ptr */
+       dma_addr_t               reply_alloc_dma;
+       MPT_FRAME_HDR           *reply_frames;  /* Reply msg frames - rounded up! */
+       dma_addr_t               reply_frames_dma;
+       u32                      reply_frames_low_dma;
+       int                      reply_depth;   /* Num Allocated reply frames */
+       int                      reply_sz;      /* Reply frame size */
+       CHIP_TYPE                chip_type;
+               /* We (host driver) get to manage our own RequestQueue! */
+       u8                      *req_alloc;     /* Request frames alloc ptr */
+       dma_addr_t               req_alloc_dma;
+       MPT_FRAME_HDR           *req_frames;    /* Request msg frames - rounded up! */
+       dma_addr_t               req_frames_dma;
+       u32                      req_frames_low_dma;
+       int                      req_depth;     /* Number of request frames */
+       int                      req_sz;        /* Request frame size (bytes) */
+       spinlock_t               FreeQlock;
+       MPT_Q_TRACKER            FreeQ;
+               /* Pool of SCSI sense buffers for commands coming from
+                * the SCSI mid-layer.  We have one 256 byte sense buffer
+                * for each REQ entry.
+                */
+       u8                      *sense_buf_pool;
+       dma_addr_t               sense_buf_pool_dma;
+       u32                      sense_buf_low_dma;
+       int                      mtrr_reg;
+       struct pci_dev          *pcidev;        /* struct pci_dev pointer */
+       u8                      *memmap;        /* mmap address */
+       struct Scsi_Host        *sh;            /* Scsi Host pointer */
+       ScsiCfgData             spi_data;       /* Scsi config. data */
+       MPT_IOCTL               *ioctl;         /* ioctl data pointer */
+       struct proc_dir_entry   *ioc_dentry;
+       struct _MPT_ADAPTER     *alt_ioc;       /* ptr to 929 bound adapter port */
+       spinlock_t               diagLock;      /* diagnostic reset lock */
+       int                      diagPending;
+       u32                      biosVersion;   /* BIOS version from IO Unit Page 2 */
+       int                      eventTypes;    /* Event logging parameters */
+       int                      eventContext;  /* Next event context */
+       int                      eventLogSize;  /* Max number of cached events */
+#ifdef MPTSCSIH_DBG_TIMEOUT
+       int                     timeout_hard;
+       int                     timeout_delta;
+       int                     timeout_cnt;
+       int                     timeout_maxcnt;
+#endif
+       struct _mpt_ioctl_events *events;       /* pointer to event log */
+       fw_image_t              **cached_fw;    /* Pointer to FW SG List */
+       Q_TRACKER                configQ;       /* linked list of config. requests */
+       int                      num_fw_frags;  /* Number of SGE in FW SG List */
+       int                      hs_reply_idx;
+#ifndef MFCNT
+       u32                      pad0;
+#else
+       u32                      mfcnt;
+#endif
+       u32                      hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
+       u16                      hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
+       IOCFactsReply_t          facts;
+       PortFactsReply_t         pfacts[2];
+       FCPortPage0_t            fc_port_page0[2];
+       LANPage0_t               lan_cnfg_page0;
+       LANPage1_t               lan_cnfg_page1;
+       u8                       FirstWhoInit;
+       u8                       upload_fw;     /* If set, do a fw upload */
+       u8                       reload_fw;     /* Force a FW Reload on next reset */
+       u8                       pad1[5];
+} MPT_ADAPTER;
+
+
+typedef struct _MPT_ADAPTER_TRACKER {
+       MPT_ADAPTER     *head;
+       MPT_ADAPTER     *tail;
+} MPT_ADAPTER_TRACKER;
+
+/*
+ *  New return value convention:
+ *    1 = Ok to free associated request frame
+ *    0 = not Ok ...
+ */
+typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
+typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply);
+typedef int (*MPT_RESETHANDLER)(MPT_ADAPTER *ioc, int reset_phase);
+/* reset_phase defs */
+#define MPT_IOC_PRE_RESET              0
+#define MPT_IOC_POST_RESET             1
+#define MPT_IOC_SETUP_RESET            2
+
+/*
+ * Invent MPT host event (super-set of MPI Events)
+ * Fitted to 1030's 64-byte [max] request frame size
+ */
+typedef struct _MPT_HOST_EVENT {
+       EventNotificationReply_t         MpiEvent;      /* 8 32-bit words! */
+       u32                              pad[6];
+       void                            *next;
+} MPT_HOST_EVENT;
+
+#define MPT_HOSTEVENT_IOC_BRINGUP      0x91
+#define MPT_HOSTEVENT_IOC_RECOVER      0x92
+
+/* Define the generic types based on the size
+ * of the dma_addr_t type.
+ */
+typedef struct _mpt_sge {
+       u32             FlagsLength;
+       dma_addr_t      Address;
+} MptSge_t;
+
+#define mpt_addr_size() \
+       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
+               MPI_SGE_FLAGS_32_BIT_ADDRESSING)
+
+#define mpt_msg_flags() \
+       ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
+               MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Funky (private) macros...
+ */
+#ifdef MPT_DEBUG
+#define dprintk(x)  printk x
+#else
+#define dprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_HANDSHAKE
+#define dhsprintk(x)  printk x
+#else
+#define dhsprintk(x)
+#endif
+
+//#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#ifdef MPT_DEBUG_MSG_FRAME
+#define dmfprintk(x)  printk x
+#else
+#define dmfprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_IRQ
+#define dirqprintk(x)  printk x
+#else
+#define dirqprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_SG
+#define dsgprintk(x)  printk x
+#else
+#define dsgprintk(x)
+#endif
+
+#if defined(MPT_DEBUG_DL) 
+//#if defined(MPT_DEBUG_DL) || defined(MPT_DEBUG)
+#define ddlprintk(x)  printk x
+#else
+#define ddlprintk(x)
+#endif
+
+
+#ifdef MPT_DEBUG_DV
+#define ddvprintk(x)  printk x
+#else
+#define ddvprintk(x)
+#endif
+
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+#define ddvtprintk(x)  printk x
+#else
+#define ddvtprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_IOCTL
+#define dctlprintk(x) printk x
+#else
+#define dctlprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_RESET
+#define dtmprintk(x) printk x
+#else
+#define dtmprintk(x)
+#endif
+
+#ifdef MPT_DEBUG_NEH
+#define nehprintk(x) printk x
+#else
+#define nehprintk(x)
+#endif
+
+#if defined(MPT_DEBUG_CONFIG) 
+//#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
+#define dcprintk(x) printk x
+#else
+#define dcprintk(x)
+#endif
+
+#if defined(MPT_DEBUG_SCSI) || defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define dsprintk(x) printk x
+#else
+#define dsprintk(x)
+#endif
+
+
+#define MPT_INDEX_2_MFPTR(ioc,idx) \
+       (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
+
+#define MFPTR_2_MPT_INDEX(ioc,mf) \
+       (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz )
+
+#define MPT_INDEX_2_RFPTR(ioc,idx) \
+       (MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) )
+
+#define Q_INIT(q,type)  (q)->head = (q)->tail = (type*)(q)
+#define Q_IS_EMPTY(q)   ((Q_ITEM*)(q)->head == (Q_ITEM*)(q))
+
+#define Q_ADD_TAIL(qt,i,type) { \
+       Q_TRACKER       *_qt = (Q_TRACKER*)(qt); \
+       Q_ITEM          *oldTail = _qt->tail; \
+       (i)->forw = (type*)_qt; \
+       (i)->back = (type*)oldTail; \
+       oldTail->forw = (Q_ITEM*)(i); \
+       _qt->tail = (Q_ITEM*)(i); \
+}
+
+#define Q_ADD_HEAD(qt,i,type) { \
+       Q_TRACKER       *_qt = (Q_TRACKER*)(qt); \
+       Q_ITEM          *oldHead = _qt->head; \
+       (i)->forw = (type*)oldHead; \
+       (i)->back = (type*)_qt; \
+       oldHead->back = (Q_ITEM*)(i); \
+       _qt->head = (Q_ITEM*)(i); \
+}
+
+#define Q_DEL_ITEM(i) { \
+       Q_ITEM  *_forw = (Q_ITEM*)(i)->forw; \
+       Q_ITEM  *_back = (Q_ITEM*)(i)->back; \
+       _back->forw = _forw; \
+       _forw->back = _back; \
+}
+
+#define SWAB4(value) \
+       (u32)(   (((value) & 0x000000ff) << 24) \
+              | (((value) & 0x0000ff00) << 8)  \
+              | (((value) & 0x00ff0000) >> 8)  \
+              | (((value) & 0xff000000) >> 24) )
+
+
+#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define DBG_DUMP_REPLY_FRAME(mfp) \
+       {       u32 *m = (u32 *)(mfp);                                  \
+               int  i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16;     \
+               printk(KERN_INFO " ");                                  \
+               for (i=0; i<n; i++)                                     \
+                       printk(" %08x", le32_to_cpu(m[i]));             \
+               printk("\n");                                           \
+       }
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \
+       {       int  i, n = 3;                                          \
+               u32 *m = (u32 *)(mfp);                                  \
+               printk(KERN_INFO " ");                                  \
+               for (i=0; i<n; i++)                                     \
+                       printk(" %08x", le32_to_cpu(m[i]));             \
+               printk("\n");                                           \
+       }
+#else
+#define DBG_DUMP_REPLY_FRAME(mfp)
+#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers
+ * Private to the driver.
+ */
+/* LOCAL structure and fields used when processing
+ * internally generated commands. These include:
+ * bus scan, dv and config requests.
+ */
+typedef struct _MPT_LOCAL_REPLY {
+       ConfigPageHeader_t header;
+       int     completion;
+       u8      sense[SCSI_STD_SENSE_BYTES];
+       u8      scsiStatus;
+       u8      skip;
+       u32     pad;
+} MPT_LOCAL_REPLY;
+
+#define MPT_HOST_BUS_UNKNOWN           (0xFF)
+#define MPT_HOST_TOO_MANY_TM           (0x05)
+#define MPT_HOST_NVRAM_INVALID         (0xFFFFFFFF)
+#define MPT_HOST_NO_CHAIN              (0xFFFFFFFF)
+#define MPT_NVRAM_MASK_TIMEOUT         (0x000000FF)
+#define MPT_NVRAM_SYNC_MASK            (0x0000FF00)
+#define MPT_NVRAM_SYNC_SHIFT           (8)
+#define MPT_NVRAM_DISCONNECT_ENABLE    (0x00010000)
+#define MPT_NVRAM_ID_SCAN_ENABLE       (0x00020000)
+#define MPT_NVRAM_LUN_SCAN_ENABLE      (0x00040000)
+#define MPT_NVRAM_TAG_QUEUE_ENABLE     (0x00080000)
+#define MPT_NVRAM_WIDE_DISABLE         (0x00100000)
+#define MPT_NVRAM_BOOT_CHOICE          (0x00200000)
+
+#ifdef MPT_SCSI_USE_NEW_EH
+/* The TM_STATE variable is used to provide strict single threading of TM
+ * requests as well as communicate TM error conditions.
+ */
+#define TM_STATE_NONE          (0)
+#define        TM_STATE_IN_PROGRESS   (1)
+#define        TM_STATE_ERROR         (2)
+#endif
+
+typedef struct _MPT_SCSI_HOST {
+       MPT_ADAPTER              *ioc;
+       int                       port;
+       u32                       pad0;
+       struct scsi_cmnd        **ScsiLookup;
+               /* Pool of buffers for chaining. ReqToChain
+                * and ChainToChain track index of chain buffers.
+                * ChainBuffer (DMA) virt/phys addresses.
+                * FreeChainQ (lock) locking mechanisms.
+                */
+       int                      *ReqToChain;
+       int                      *ChainToChain;
+       u8                       *ChainBuffer;
+       dma_addr_t                ChainBufferDMA;
+       MPT_Q_TRACKER             FreeChainQ;
+       spinlock_t                FreeChainQlock;
+       u32                       qtag_tick;
+       VirtDevice              **Targets;
+       MPT_LOCAL_REPLY          *pLocal;               /* used for internal commands */
+       struct timer_list         timer;
+       struct timer_list         TMtimer;              /* Timer for TM commands ONLY */
+               /* Pool of memory for holding SCpnts before doing
+                * OS callbacks. freeQ is the free pool.
+                */
+       u8                       *memQ;
+       DONE_Q_TRACKER            freeQ;
+       DONE_Q_TRACKER            doneQ;                /* Holds Linux formmatted requests */
+       DONE_Q_TRACKER            pendingQ;             /* Holds MPI formmatted requests */
+       MPT_Q_TRACKER             taskQ;                /* TM request Q */
+       spinlock_t                freedoneQlock;
+       int                       taskQcnt;
+       int                       num_chain;            /* Number of chain buffers */
+       int                       max_sge;              /* Max No of SGE*/
+       u8                        numTMrequests;
+       u8                        tmPending;
+       u8                        resetPending;
+       u8                        is_spi;               /* Parallel SCSI i/f */
+       u8                        negoNvram;            /* DV disabled, nego NVRAM */
+       u8                        is_multipath;         /* Multi-path compatible */
+#ifdef MPT_SCSI_USE_NEW_EH
+       u8                        tmState;
+       u8                        rsvd[1];
+#else
+       u8                        rsvd[2];
+#endif
+       MPT_FRAME_HDR            *tmPtr;                /* Ptr to TM request*/
+       MPT_FRAME_HDR            *cmdPtr;               /* Ptr to nonOS request */
+       struct scsi_cmnd         *abortSCpnt;
+       MPT_LOCAL_REPLY           localReply;           /* internal cmd reply struct */
+       unsigned long             hard_resets;          /* driver forced bus resets count */
+       unsigned long             soft_resets;          /* fw/external bus resets count */
+       unsigned long             timeouts;             /* cmd timeouts */
+       ushort                    sel_timeout[MPT_MAX_FC_DEVICES];
+} MPT_SCSI_HOST;
+
+/*
+ *     Structure for overlaying onto scsi_cmnd->SCp area
+ *     NOTE: SCp area is 36 bytes min, 44 bytes max?
+ */
+typedef struct _scPrivate {
+       struct scsi_cmnd        *forw;
+       struct scsi_cmnd        *back;
+       void                    *p1;
+       void                    *p2;
+       u8                       io_path_id;    /* DMP */
+       u8                       pad[7];
+} scPrivate;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     More Dynamic Multi-Pathing stuff...
+ */
+
+/* Forward decl, a strange C thing, to prevent gcc compiler warnings */
+struct scsi_cmnd;
+
+/*
+ *     DMP service layer structure / API interface
+ */
+typedef struct _DmpServices {
+       VirtDevTracker    VdevList;
+       struct semaphore *Daemon;
+       int             (*ScsiPathSelect)
+                               (struct scsi_cmnd *, MPT_SCSI_HOST **hd, int *target, int *lun);
+       int             (*DmpIoDoneChk)
+                               (MPT_SCSI_HOST *, struct scsi_cmnd *,
+                                SCSIIORequest_t *,
+                                SCSIIOReply_t *);
+       void            (*mptscsih_scanVlist)
+                               (MPT_SCSI_HOST *, int portnum);
+       int             (*ScsiAbort)
+                               (struct scsi_cmnd *);
+       int             (*ScsiBusReset)
+                               (struct scsi_cmnd *);
+} DmpServices_t;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Generic structure passed to the base mpt_config function.
+ */
+typedef struct _x_config_parms {
+       Q_ITEM                   linkage;       /* linked list */
+       struct timer_list        timer;         /* timer function for this request  */
+       ConfigPageHeader_t      *hdr;
+       dma_addr_t               physAddr;
+       int                      wait_done;     /* wait for this request */
+       u32                      pageAddr;      /* properly formatted */
+       u8                       action;
+       u8                       dir;
+       u8                       timeout;       /* seconds */
+       u8                       pad1;
+       u16                      status;
+       u16                      pad2;
+} CONFIGPARMS;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Public entry points...
+ */
+extern int      mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void     mpt_deregister(int cb_idx);
+extern int      mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void     mpt_event_deregister(int cb_idx);
+extern int      mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func);
+extern void     mpt_reset_deregister(int cb_idx);
+extern int      mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable);
+extern void     mpt_deregister_ascqops_strings(void);
+extern MPT_FRAME_HDR   *mpt_get_msg_frame(int handle, int iocid);
+extern void     mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern void     mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf);
+extern void     mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
+extern void     mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr);
+
+extern int      mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag);
+extern int      mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag);
+extern int      mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
+extern MPT_ADAPTER     *mpt_adapter_find_first(void);
+extern MPT_ADAPTER     *mpt_adapter_find_next(MPT_ADAPTER *prev);
+extern u32      mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+extern void     mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
+extern int      mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int      mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
+extern void    *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz);
+extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img);
+extern int      mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
+
+/*
+ *  Public data decl's...
+ */
+extern MPT_ADAPTER             *mpt_adapters[MPT_MAX_ADAPTERS];
+extern struct proc_dir_entry   *mpt_proc_root_dir;
+extern DmpServices_t           *DmpService;
+
+extern int               mpt_lan_index;        /* needed by mptlan.c */
+extern int               mpt_stm_index;        /* needed by mptstm.c */
+
+extern void             *mpt_v_ASCQ_TablePtr;
+extern const char      **mpt_ScsiOpcodesPtr;
+extern int               mpt_ASCQ_TableSz;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif         /* } __KERNEL__ */
+
+/*
+ *  More (public) macros...
+ */
+#ifndef MIN
+#define MIN(a, b)   (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)   (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef offsetof
+#define offsetof(t, m) ((size_t) (&((t *)0)->m))
+#endif
+
+#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__)
+#define CAST_U32_TO_PTR(x)     ((void *)(u64)x)
+#define CAST_PTR_TO_U32(x)     ((u32)(u64)x)
+#else
+#define CAST_U32_TO_PTR(x)     ((void *)x)
+#define CAST_PTR_TO_U32(x)     ((u32)x)
+#endif
+
+#define MPT_PROTOCOL_FLAGS_c_c_c_c(pflags) \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_INITIATOR)   ? 'I' : 'i',    \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET)      ? 'T' : 't',    \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN)         ? 'L' : 'l',    \
+       ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR)  ? 'B' : 'b'
+
+/*
+ *  Shifted SGE Defines - Use in SGE with FlagsLength member.
+ *  Otherwise, use MPI_xxx defines (refer to "lsi/mpi.h" header).
+ *  Defaults: 32 bit SGE, SYSTEM_ADDRESS if direction bit is 0, read
+ */
+#define MPT_TRANSFER_IOC_TO_HOST               (0x00000000)
+#define MPT_TRANSFER_HOST_TO_IOC               (0x04000000)
+#define MPT_SGE_FLAGS_LAST_ELEMENT             (0x80000000)
+#define MPT_SGE_FLAGS_END_OF_BUFFER            (0x40000000)
+#define MPT_SGE_FLAGS_LOCAL_ADDRESS            (0x08000000)
+#define MPT_SGE_FLAGS_DIRECTION                        (0x04000000)
+#define MPT_SGE_FLAGS_ADDRESSING               (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
+#define MPT_SGE_FLAGS_END_OF_LIST              (0x01000000)
+
+#define MPT_SGE_FLAGS_TRANSACTION_ELEMENT      (0x00000000)
+#define MPT_SGE_FLAGS_SIMPLE_ELEMENT           (0x10000000)
+#define MPT_SGE_FLAGS_CHAIN_ELEMENT            (0x30000000)
+#define MPT_SGE_FLAGS_ELEMENT_MASK             (0x30000000)
+
+#define MPT_SGE_FLAGS_SSIMPLE_READ \
+       (MPT_SGE_FLAGS_LAST_ELEMENT |   \
+        MPT_SGE_FLAGS_END_OF_BUFFER |  \
+        MPT_SGE_FLAGS_END_OF_LIST |    \
+        MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
+        MPT_SGE_FLAGS_ADDRESSING | \
+        MPT_TRANSFER_IOC_TO_HOST)
+#define MPT_SGE_FLAGS_SSIMPLE_WRITE \
+       (MPT_SGE_FLAGS_LAST_ELEMENT |   \
+        MPT_SGE_FLAGS_END_OF_BUFFER |  \
+        MPT_SGE_FLAGS_END_OF_LIST |    \
+        MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
+        MPT_SGE_FLAGS_ADDRESSING | \
+        MPT_TRANSFER_HOST_TO_IOC)
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
+
diff --git a/xen/drivers/message/fusion/mptscsih.c b/xen/drivers/message/fusion/mptscsih.c
new file mode 100644 (file)
index 0000000..5a8a78a
--- /dev/null
@@ -0,0 +1,7948 @@
+/*
+ *  linux/drivers/message/fusion/mptscsih.c
+ *      High performance SCSI / Fibre Channel SCSI Host device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ *      and countless enhancements while adding support for the 1030
+ *      chip family.  Pam has been instrumental in the development of
+ *      of the 2.xx.xx series fusion drivers, and her contributions are
+ *      far too numerous to hope to list in one place.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see mptbase.c)
+ *
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
+ *  Original author: Steven J. Ralston
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:lstephens@lsil.com)
+ *
+ *  $Id: mptscsih.c,v 1.1.2.4 2003/05/07 14:08:34 pdelaney Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <xeno/types.h>        /* SAE: Necessary... */
+#include <xeno/module.h>
+#include <xeno/version.h>
+#include <xeno/kernel.h>
+#include <xeno/init.h>
+#include <xeno/errno.h>
+#include <xeno/kdev_t.h>
+#include <xeno/blkdev.h>
+#include <xeno/blk.h>          /* for io_request_lock (spinlock) decl */
+#include <xeno/delay.h>        /* for mdelay */
+#include <xeno/interrupt.h>    /* needed for in_interrupt() proto */
+#include <xeno/reboot.h>       /* notifier code */
+#include <xeno/tqueue.h>
+#include <asm/byteorder.h>     /* SAE: Necessary... */
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
+#include "../../scsi/sd.h"
+#endif
+
+#include "mptbase.h"
+#include "mptscsih.h"
+#include "isense.h"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#define my_NAME                "Fusion MPT SCSI Host driver"
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
+#define MYNAM          "mptscsih"
+
+MODULE_AUTHOR(MODULEAUTHOR);
+MODULE_DESCRIPTION(my_NAME);
+MODULE_LICENSE("GPL");
+
+/* Set string for command line args from insmod */
+#ifdef MODULE
+char *mptscsih = 0;
+MODULE_PARM(mptscsih, "s");
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+typedef struct _BIG_SENSE_BUF {
+       u8              data[MPT_SENSE_BUFFER_ALLOC];
+} BIG_SENSE_BUF;
+
+#define MPT_SCANDV_GOOD                        (0x00000000) /* must be 0 */
+#define MPT_SCANDV_DID_RESET           (0x00000001)
+#define MPT_SCANDV_SENSE               (0x00000002)
+#define MPT_SCANDV_SOME_ERROR          (0x00000004)
+#define MPT_SCANDV_SELECTION_TIMEOUT   (0x00000008)
+#define MPT_SCANDV_ISSUE_SENSE         (0x00000010)
+
+#define MPT_SCANDV_MAX_RETRIES         (10)
+
+#define MPT_ICFLAG_BUF_CAP     0x01    /* ReadBuffer Read Capacity format */
+#define MPT_ICFLAG_ECHO                0x02    /* ReadBuffer Echo buffer format */
+#define MPT_ICFLAG_PHYS_DISK   0x04    /* Any SCSI IO but do Phys Disk Format */
+#define MPT_ICFLAG_TAGGED_CMD  0x08    /* Do tagged IO */
+#define MPT_ICFLAG_DID_RESET   0x20    /* Bus Reset occured with this command */
+#define MPT_ICFLAG_RESERVED    0x40    /* Reserved has been issued */
+
+typedef struct _internal_cmd {
+       char            *data;          /* data pointer */
+       dma_addr_t      data_dma;       /* data dma address */
+       int             size;           /* transfer size */
+       u8              cmd;            /* SCSI Op Code */
+       u8              bus;            /* bus number */
+       u8              id;             /* SCSI ID (virtual) */
+       u8              lun;
+       u8              flags;          /* Bit Field - See above */
+       u8              physDiskNum;    /* Phys disk number, -1 else */
+       u8              rsvd2;
+       u8              rsvd;
+} INTERNAL_CMD;
+
+typedef struct _negoparms {
+       u8 width;
+       u8 offset;
+       u8 factor;
+       u8 flags;
+} NEGOPARMS;
+
+typedef struct _dv_parameters {
+       NEGOPARMS        max;
+       NEGOPARMS        now;
+       u8               cmd;
+       u8               id;
+       u16              pad1;
+} DVPARAMETERS;
+
+
+/*
+ *  Other private/forward protos...
+ */
+static int     mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void    mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
+static int     mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+
+static int     mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+                                SCSIIORequest_t *pReq, int req_idx);
+static void    mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
+static int     mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
+static void    copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
+#ifndef MPT_SCSI_USE_NEW_EH
+static void    search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
+#else
+static int     mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
+#endif
+static u32     SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc);
+static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
+static void    post_pendingQ_commands(MPT_SCSI_HOST *hd);
+
+static int     mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag);
+static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag);
+
+static int     mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
+static int     mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+
+static VirtDevice      *mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
+void           mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
+static void    mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+static void    mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
+static void    mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
+static int     mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
+static int     mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
+static void    mptscsih_timer_expired(unsigned long data);
+static void    mptscsih_taskmgmt_timeout(unsigned long data);
+static int     mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
+static int     mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+static int     mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
+static void    mptscsih_domainValidation(void *hd);
+static int     mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
+static void    mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
+static int     mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
+static void    mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
+static void    mptscsih_fillbuf(char *buffer, int size, int index, int width);
+#endif
+static int     mptscsih_setup(char *str);
+static int     mptscsih_halt(struct notifier_block *nb, ulong event, void *buf);
+
+#if XENO_KILLED
+/*
+ *     Reboot Notification
+ */
+static struct notifier_block mptscsih_notifier = {
+       mptscsih_halt, NULL, 0
+};
+#endif
+
+/*
+ *     Private data...
+ */
+
+static int     mpt_scsi_hosts = 0;
+static atomic_t        queue_depth;
+
+static int     ScsiDoneCtx = -1;
+static int     ScsiTaskCtx = -1;
+static int     ScsiScanDvCtx = -1; /* Used only for bus scan and dv */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28)
+static struct proc_dir_entry proc_mpt_scsihost =
+{
+       .low_ino =      PROC_SCSI_MPT,
+       .namelen =      8,
+       .name =         "mptscsih",
+       .mode =         S_IFDIR | S_IRUGO | S_IXUGO,
+       .nlink =        2,
+};
+#endif
+
+#define SNS_LEN(scp)   sizeof((scp)->sense_buffer)
+
+#ifndef MPT_SCSI_USE_NEW_EH
+/*
+ *  Stuff to handle single-threading SCSI TaskMgmt
+ *  (abort/reset) requests...
+ */
+static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
+static int mytaskQ_bh_active = 0;
+static struct mpt_work_struct  mptscsih_ptaskfoo;
+static atomic_t        mpt_taskQdepth;
+#endif
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*
+ * Domain Validation task structure
+ */
+static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
+static int dvtaskQ_active = 0;
+static int dvtaskQ_release = 0;
+static struct mpt_work_struct  mptscsih_dvTask;
+#endif
+
+/* SAE: No wait queues in Xen */
+#ifdef XENO_KILLED
+/*
+ * Wait Queue setup
+ */
+static DECLARE_WAIT_QUEUE_HEAD (scandv_waitq);
+
+#endif
+
+static int scandv_wait_done = 1;
+
+/* Driver default setup
+ */
+static struct mptscsih_driver_setup
+       driver_setup = MPTSCSIH_DRIVER_SETUP;
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+static Scsi_Cmnd *foo_to[8];
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private inline routines...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 19991030 -sralston
+ *  Return absolute SCSI data direction:
+ *     1 = _DATA_OUT
+ *     0 = _DIR_NONE
+ *    -1 = _DATA_IN
+ *
+ * Changed: 3-20-2002 pdelaney to use the default data
+ * direction and the defines set up in the
+ * 2.4 kernel series
+ *     1 = _DATA_OUT   changed to SCSI_DATA_WRITE (1)
+ *     0 = _DIR_NONE   changed to SCSI_DATA_NONE (3)
+ *    -1 = _DATA_IN    changed to SCSI_DATA_READ (2)
+ * If the direction is unknown, fall through to original code.
+ *
+ * Mid-layer bug fix(): sg interface generates the wrong data
+ * direction in some cases. Set the direction the hard way for
+ * the most common commands.
+ */
+static inline int
+mptscsih_io_direction(Scsi_Cmnd *cmd)
+{
+       switch (cmd->cmnd[0]) {
+       case WRITE_6:           
+       case WRITE_10:          
+               return SCSI_DATA_WRITE;
+               break;
+       case READ_6:            
+       case READ_10:           
+               return SCSI_DATA_READ;
+               break;
+       }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN)
+               return cmd->sc_data_direction;
+#endif
+       switch (cmd->cmnd[0]) {
+       /*  _DATA_OUT commands  */
+       case WRITE_6:           case WRITE_10:          case WRITE_12:
+       case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
+       case WRITE_VERIFY:      case WRITE_VERIFY_12:
+       case COMPARE:           case COPY:              case COPY_VERIFY:
+       case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
+       case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:
+       case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
+       case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
+       case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
+       case REASSIGN_BLOCKS:
+       case PERSISTENT_RESERVE_OUT:
+       case 0xea:
+       case 0xa3:
+               return SCSI_DATA_WRITE;
+
+       /*  No data transfer commands  */
+       case SEEK_6:            case SEEK_10:
+       case RESERVE:           case RELEASE:
+       case TEST_UNIT_READY:
+       case START_STOP:
+       case ALLOW_MEDIUM_REMOVAL:
+               return SCSI_DATA_NONE;
+
+       /*  Conditional data transfer commands  */
+       case FORMAT_UNIT:
+               if (cmd->cmnd[1] & 0x10)        /* FmtData (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
+
+       case VERIFY:
+               if (cmd->cmnd[1] & 0x02)        /* VERIFY:BYTCHK (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
+
+       case RESERVE_10:
+               if (cmd->cmnd[1] & 0x03)        /* RESERVE:{LongID|Extent} (data out phase)? */
+                       return SCSI_DATA_WRITE;
+               else
+                       return SCSI_DATA_NONE;
+
+       /*  Must be data _IN!  */
+       default:
+               return SCSI_DATA_READ;
+       }
+} /* mptscsih_io_direction() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_add_sge - Place a simple SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @flagslength: SGE flags and data transfer length
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+static inline void
+mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
+
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pSge->Address.High = cpu_to_le32(tmp);
+
+       } else {
+               SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
+               pSge->FlagsLength = cpu_to_le32(flagslength);
+               pSge->Address = cpu_to_le32(dma_addr);
+       }
+} /* mptscsih_add_sge() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_add_chain - Place a chain SGE at address pAddr.
+ *     @pAddr: virtual address for SGE
+ *     @next: nextChainOffset value (u32's)
+ *     @length: length of next SGL segment
+ *     @dma_addr: Physical address
+ *
+ *     This routine places a MPT request frame back on the MPT adapter's
+ *     FreeQ.
+ */
+static inline void
+mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
+{
+       if (sizeof(dma_addr_t) == sizeof(u64)) {
+               SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
+               u32 tmp = dma_addr & 0xFFFFFFFF;
+
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+
+               pChain->NextChainOffset = next;
+
+               pChain->Address.Low = cpu_to_le32(tmp);
+               tmp = (u32) ((u64)dma_addr >> 32);
+               pChain->Address.High = cpu_to_le32(tmp);
+       } else {
+               SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
+               pChain->Length = cpu_to_le16(length);
+               pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
+               pChain->NextChainOffset = next;
+               pChain->Address = cpu_to_le32(dma_addr);
+       }
+} /* mptscsih_add_chain() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_getFreeChainBuffes - Function to get a free chain
+ *     from the MPT_SCSI_HOST FreeChainQ.
+ *     @hd: Pointer to the MPT_SCSI_HOST instance
+ *     @req_idx: Index of the SCSI IO request frame. (output)
+ *
+ *     return SUCCESS or FAILED
+ */
+static inline int
+mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex)
+{
+       MPT_FRAME_HDR *chainBuf = NULL;
+       unsigned long flags;
+       int rc = FAILED;
+       int chain_idx = MPT_HOST_NO_CHAIN;
+
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (!Q_IS_EMPTY(&hd->FreeChainQ)) {
+
+               int offset;
+
+               chainBuf = hd->FreeChainQ.head;
+               Q_DEL_ITEM(&chainBuf->u.frame.linkage);
+               offset = (u8 *)chainBuf - (u8 *)hd->ChainBuffer;
+               chain_idx = offset / hd->ioc->req_sz;
+               rc = SUCCESS;
+       }
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+
+       *retIndex = chain_idx;
+
+       dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n",
+                       hd->ioc->name, *retIndex, chainBuf));
+
+       return rc;
+} /* mptscsih_getFreeChainBuffer() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_AddSGE - Add a SGE (plus chain buffers) to the
+ *     SCSIIORequest_t Message Frame.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @SCpnt: Pointer to Scsi_Cmnd structure
+ *     @pReq: Pointer to SCSIIORequest_t structure
+ *
+ *     Returns ...
+ */
+static int
+mptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,
+               SCSIIORequest_t *pReq, int req_idx)
+{
+       char    *psge;
+       char    *chainSge;
+       struct scatterlist *sg;
+       int      frm_sz;
+       int      sges_left, sg_done;
+       int      chain_idx = MPT_HOST_NO_CHAIN;
+       int      sgeOffset;
+       int      numSgeSlots, numSgeThisFrame;
+       u32      sgflags, sgdir, thisxfer = 0;
+       int      chain_dma_off = 0;
+       int      newIndex;
+       int      ii;
+       dma_addr_t v2;
+
+       sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;
+       if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {
+               sgdir = MPT_TRANSFER_HOST_TO_IOC;
+       } else {
+               sgdir = MPT_TRANSFER_IOC_TO_HOST;
+       }
+
+       psge = (char *) &pReq->SGL;
+       frm_sz = hd->ioc->req_sz;
+
+       /* Map the data portion, if any.
+        * sges_left  = 0 if no data transfer.
+        */
+       sges_left = SCpnt->use_sg;
+       if (SCpnt->use_sg) {
+               sges_left = pci_map_sg(hd->ioc->pcidev,
+                              (struct scatterlist *) SCpnt->request_buffer,
+                              SCpnt->use_sg,
+                              scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+       } else if (SCpnt->request_bufflen) {
+               dma_addr_t       buf_dma_addr;
+               scPrivate       *my_priv;
+
+               buf_dma_addr = pci_map_single(hd->ioc->pcidev,
+                                     SCpnt->request_buffer,
+                                     SCpnt->request_bufflen,
+                                     scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+
+               /* We hide it here for later unmap. */
+               my_priv = (scPrivate *) &SCpnt->SCp;
+               my_priv->p1 = (void *)(ulong) buf_dma_addr;
+
+               dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
+                               hd->ioc->name, SCpnt, SCpnt->request_bufflen));
+
+               mptscsih_add_sge((char *) &pReq->SGL,
+                       0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
+                       buf_dma_addr);
+
+               return SUCCESS;
+       }
+
+       /* Handle the SG case.
+        */
+       sg = (struct scatterlist *) SCpnt->request_buffer;
+       sg_done  = 0;
+       sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
+       chainSge = NULL;
+
+       /* Prior to entering this loop - the following must be set
+        * current MF:  sgeOffset (bytes)
+        *              chainSge (Null if original MF is not a chain buffer)
+        *              sg_done (num SGE done for this MF)
+        */
+
+nextSGEset:
+       numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );
+       numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;
+
+       sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;
+
+       /* Get first (num - 1) SG elements
+        * Skip any SG entries with a length of 0
+        * NOTE: at finish, sg and psge pointed to NEXT data/location positions
+        */
+       for (ii=0; ii < (numSgeThisFrame-1); ii++) {
+               thisxfer = sg_dma_len(sg);
+               if (thisxfer == 0) {
+                       sg ++; /* Get next SG element from the OS */
+                       sg_done++;
+                       continue;
+               }
+
+               v2 = sg_dma_address(sg);
+               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+
+               sg++;           /* Get next SG element from the OS */
+               psge += (sizeof(u32) + sizeof(dma_addr_t));
+               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               sg_done++;
+       }
+
+       if (numSgeThisFrame == sges_left) {
+               /* Add last element, end of buffer and end of list flags.
+                */
+               sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |
+                               MPT_SGE_FLAGS_END_OF_BUFFER |
+                               MPT_SGE_FLAGS_END_OF_LIST;
+
+               /* Add last SGE and set termination flags.
+                * Note: Last SGE may have a length of 0 - which should be ok.
+                */
+               thisxfer = sg_dma_len(sg);
+
+               v2 = sg_dma_address(sg);
+               mptscsih_add_sge(psge, sgflags | thisxfer, v2);
+               /*
+               sg++;
+               psge += (sizeof(u32) + sizeof(dma_addr_t));
+               */
+               sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+               sg_done++;
+
+               if (chainSge) {
+                       /* The current buffer is a chain buffer,
+                        * but there is not another one.
+                        * Update the chain element
+                        * Offset and Length fields.
+                        */
+                       mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
+               } else {
+                       /* The current buffer is the original MF
+                        * and there is no Chain buffer.
+                        */
+                       pReq->ChainOffset = 0;
+               }
+       } else {
+               /* At least one chain buffer is needed.
+                * Complete the first MF
+                *  - last SGE element, set the LastElement bit
+                *  - set ChainOffset (words) for orig MF
+                *             (OR finish previous MF chain buffer)
+                *  - update MFStructPtr ChainIndex
+                *  - Populate chain element
+                * Also
+                * Loop until done.
+                */
+
+               dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
+                               hd->ioc->name, sg_done));
+
+               /* Set LAST_ELEMENT flag for last non-chain element
+                * in the buffer. Since psge points at the NEXT
+                * SGE element, go back one SGE element, update the flags
+                * and reset the pointer. (Note: sgflags & thisxfer are already
+                * set properly).
+                */
+               if (sg_done) {
+                       u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));
+                       sgflags = le32_to_cpu(*ptmp);
+                       sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;
+                       *ptmp = cpu_to_le32(sgflags);
+               }
+
+               if (chainSge) {
+                       /* The current buffer is a chain buffer.
+                        * chainSge points to the previous Chain Element.
+                        * Update its chain element Offset and Length (must
+                        * include chain element size) fields.
+                        * Old chain element is now complete.
+                        */
+                       u8 nextChain = (u8) (sgeOffset >> 2);
+                       sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
+                       mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);
+               } else {
+                       /* The original MF buffer requires a chain buffer -
+                        * set the offset.
+                        * Last element in this MF is a chain element.
+                        */
+                       pReq->ChainOffset = (u8) (sgeOffset >> 2);
+               }
+
+               sges_left -= sg_done;
+
+
+               /* NOTE: psge points to the beginning of the chain element
+                * in current buffer. Get a chain buffer.
+                */
+               if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)
+                       return FAILED;
+
+               /* Update the tracking arrays.
+                * If chainSge == NULL, update ReqToChain, else ChainToChain
+                */
+               if (chainSge) {
+                       hd->ChainToChain[chain_idx] = newIndex;
+               } else {
+                       hd->ReqToChain[req_idx] = newIndex;
+               }
+               chain_idx = newIndex;
+               chain_dma_off = hd->ioc->req_sz * chain_idx;
+
+               /* Populate the chainSGE for the current buffer.
+                * - Set chain buffer pointer to psge and fill
+                *   out the Address and Flags fields.
+                */
+               chainSge = (char *) psge;
+               dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
+                               psge, req_idx));
+
+               /* Start the SGE for the next buffer
+                */
+               psge = (char *) (hd->ChainBuffer + chain_dma_off);
+               sgeOffset = 0;
+               sg_done = 0;
+
+               dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
+                               psge, chain_idx));
+
+               /* Start the SGE for the next buffer
+                */
+
+               goto nextSGEset;
+       }
+
+       return SUCCESS;
+} /* mptscsih_AddSGE() */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_io_done - Main SCSI IO callback routine registered to
+ *     Fusion MPT (base) driver
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @r: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *     This routine is called from mpt.c::mpt_interrupt() at the completion
+ *     of any SCSI IO request.
+ *     This routine is registered with the Fusion MPT (base) driver at driver
+ *     load/init time via the mpt_register() API call.
+ *
+ *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       Scsi_Cmnd       *sc;
+       MPT_SCSI_HOST   *hd;
+       SCSIIORequest_t *pScsiReq;
+       SCSIIOReply_t   *pScsiReply;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+       unsigned long    flags;
+#endif
+       u16              req_idx;
+
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n",
+                               ioc->name, mf?"BAD":"NULL", (void *) mf);
+               return 0;
+       }
+
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       sc = hd->ScsiLookup[req_idx];
+       if (sc == NULL) {
+               MPIHeader_t *hdr = (MPIHeader_t *)mf;
+
+               atomic_dec(&queue_depth);
+
+               /* Remark: writeSDP1 will use the ScsiDoneCtx
+                * If a SCSI I/O cmd, device disabled by OS and
+                * completion done. Cannot touch sc struct. Just free mem.
+                */
+               if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
+                       printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
+
+               mptscsih_freeChainBuffers(hd, req_idx);
+               return 1;
+       }
+
+       dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
+                       ioc->name, mf, mr, sc, req_idx));
+
+       atomic_dec(&queue_depth);
+
+       sc->result = DID_OK << 16;              /* Set default reply as OK */
+       pScsiReq = (SCSIIORequest_t *) mf;
+       pScsiReply = (SCSIIOReply_t *) mr;
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+       if (ioc->timeout_cnt > 0) {
+               int ii, left = 0;
+
+               for (ii=0; ii < 8; ii++) {
+                       if (sc == foo_to[ii]) {
+                               printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n",
+                                       ioc->name, sc, jiffies);
+                               foo_to[ii] = NULL;
+                       }
+                       if (foo_to[ii] != NULL)
+                               left++;
+               }
+
+               if (left == 0) {
+                       ioc->timeout_maxcnt = 0;
+                       ioc->timeout_cnt = 0;
+               }
+       }
+#endif
+       if (pScsiReply == NULL) {
+               /* special context reply handling */
+
+               /* If regular Inquiry cmd - save inquiry data
+                */
+               if (pScsiReq->CDB[0] == INQUIRY && !(pScsiReq->CDB[1] & 0x3)) {
+                       int      dlen;
+
+                       dlen = le32_to_cpu(pScsiReq->DataLength);
+                       if (dlen >= SCSI_STD_INQUIRY_BYTES) {
+                               mptscsih_initTarget(hd,
+                                               sc->channel,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               dlen);
+                       }
+               }
+       } else {
+               u32      xfer_cnt;
+               u16      status;
+               u8       scsi_state;
+
+               status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+               scsi_state = pScsiReply->SCSIState;
+
+               dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",
+                               ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
+                               mf, mr, sc));
+               dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"
+                               ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+                               status, scsi_state, pScsiReply->SCSIStatus,
+                               le32_to_cpu(pScsiReply->IOCLogInfo)));
+
+               if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
+                       copy_sense_data(sc, hd, mf, pScsiReply);
+
+               /*
+                *  Look for + dump FCP ResponseInfo[]!
+                */
+               if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
+                       dprintk((KERN_NOTICE "  FCP_ResponseInfo=%08xh\n",
+                                            le32_to_cpu(pScsiReply->ResponseInfo)));
+               }
+
+               switch(status) {
+               case MPI_IOCSTATUS_BUSY:                        /* 0x0002 */
+                       /* CHECKME!
+                        * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
+                        * But not: DID_BUS_BUSY lest one risk
+                        * killing interrupt handler:-(
+                        */
+                       sc->result = STS_BUSY;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_INVALID_BUS:            /* 0x0041 */
+               case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:       /* 0x0042 */
+                       sc->result = DID_BAD_TARGET << 16;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+                       /* Spoof to SCSI Selection Timeout! */
+                       sc->result = DID_NO_CONNECT << 16;
+
+                       if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
+                               hd->sel_timeout[pScsiReq->TargetID]++;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       search_taskQ_for_cmd(sc, hd);
+#endif
+                       /* Linux handles an unsolicited DID_RESET better
+                        * than an unsolicited DID_ABORT.
+                        */
+                       sc->result = DID_RESET << 16;
+
+                       /* GEM Workaround. */
+                       if (hd->is_spi)
+                               mptscsih_no_negotiate(hd, sc->target);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       search_taskQ_for_cmd(sc, hd);
+#endif
+                       sc->result = DID_RESET << 16;
+
+                       /* GEM Workaround. */
+                       if (hd->is_spi)
+                               mptscsih_no_negotiate(hd, sc->target);
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
+               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
+                       /*
+                        *  YIKES!  I just discovered that SCSI IO which
+                        *  returns check condition, SenseKey=05 (ILLEGAL REQUEST)
+                        *  and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific),
+                        *  comes down this path!
+                        *  Do upfront check for valid SenseData and give it
+                        *  precedence!
+                        */
+                       sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+                       if (scsi_state == 0) {
+                               ;
+                       } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                               /* Have already saved the status and sense data
+                                */
+                               ;
+                       } else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+                               /* What to do?
+                                */
+                               sc->result = DID_SOFT_ERROR << 16;
+                       }
+                       else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
+                               /*  Not real sure here either...  */
+                               sc->result = DID_RESET << 16;
+                       }
+
+                       /* Give report and update residual count.
+                        */
+                       xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+                       dprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+                                       sc->underflow));
+                       dprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+                       sc->resid = sc->request_bufflen - xfer_cnt;
+                       dprintk((KERN_NOTICE "  SET sc->resid=%02xh\n", sc->resid));
+#endif
+
+                       /* Report Queue Full
+                        */
+                       if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+                               mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+                       /* If regular Inquiry cmd and some data was transferred,
+                        * save inquiry data
+                        */
+                       if (    pScsiReq->CDB[0] == INQUIRY
+                            && !(pScsiReq->CDB[1] & 0x3)
+                            && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
+                          ) {
+                               mptscsih_initTarget(hd,
+                                               sc->channel,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               xfer_cnt);
+                       }
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
+               case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
+                       sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+                       if (scsi_state == 0) {
+                               ;
+                       } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                               /*
+                                * If running against circa 200003dd 909 MPT f/w,
+                                * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
+                                * (QUEUE_FULL) returned from device! --> get 0x0000?128
+                                * and with SenseBytes set to 0.
+                                */
+                               if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
+                                       mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+                               /* ADDED 20011120 -sralston
+                                * Scsi mid-layer (old_eh) doesn't seem to like it
+                                * when RAID returns SCSIStatus=02 (CHECK CONDITION),
+                                * SenseKey=01 (RECOVERED ERROR), ASC/ASCQ=95/01.
+                                * Seems to be * treating this as a IO error:-(
+                                *
+                                * So just lie about it altogether here.
+                                *
+                                * NOTE: It still gets reported to syslog via
+                                * mpt_ScsiHost_ErrorReport from copy_sense_data
+                                * call far above.
+                                */
+                               if (    pScsiReply->SCSIStatus == STS_CHECK_CONDITION
+                                    && SD_Sense_Key(sc->sense_buffer) == SK_RECOVERED_ERROR
+                                  ) {
+                                       sc->result = 0;
+                               }
+#endif
+
+                       }
+                       else if (scsi_state &
+                                (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
+                          ) {
+                               /*
+                                * What to do?
+                                */
+                               sc->result = DID_SOFT_ERROR << 16;
+                       }
+                       else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
+                               /*  Not real sure here either...  */
+                               sc->result = DID_RESET << 16;
+                       }
+                       else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+                               /* Device Inq. data indicates that it supports
+                                * QTags, but rejects QTag messages.
+                                * This command completed OK.
+                                *
+                                * Not real sure here either so do nothing...  */
+                       }
+
+                       if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)
+                               mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);
+
+                       /* Add handling of:
+                        * Reservation Conflict, Busy,
+                        * Command Terminated, CHECK
+                        */
+
+                       /* If regular Inquiry cmd - save inquiry data
+                        */
+                       xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
+                       if (    sc->result == (DID_OK << 16)
+                            && pScsiReq->CDB[0] == INQUIRY
+                            && !(pScsiReq->CDB[1] & 0x3)
+                            && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
+                          ) {
+                               mptscsih_initTarget(hd,
+                                               sc->channel,
+                                               sc->target,
+                                               pScsiReq->LUN[1],
+                                               sc->buffer,
+                                               xfer_cnt);
+                       }
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+                       if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+                               /*  Not real sure here either...  */
+                               sc->result = DID_RESET << 16;
+                       } else
+                               sc->result = DID_SOFT_ERROR << 16;
+                       break;
+
+               case MPI_IOCSTATUS_INVALID_FUNCTION:            /* 0x0001 */
+               case MPI_IOCSTATUS_INVALID_SGL:                 /* 0x0003 */
+               case MPI_IOCSTATUS_INTERNAL_ERROR:              /* 0x0004 */
+               case MPI_IOCSTATUS_RESERVED:                    /* 0x0005 */
+               case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:      /* 0x0006 */
+               case MPI_IOCSTATUS_INVALID_FIELD:               /* 0x0007 */
+               case MPI_IOCSTATUS_INVALID_STATE:               /* 0x0008 */
+               case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:           /* 0x0044 */
+               case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
+               case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:       /* 0x004A */
+               default:
+                       /*
+                        * What to do?
+                        */
+                       sc->result = DID_SOFT_ERROR << 16;
+                       break;
+
+               }       /* switch(status) */
+
+               dprintk((KERN_NOTICE "  sc->result set to %08xh\n", sc->result));
+       } /* end of address reply case */
+
+       /* Unmap the DMA buffers, if any. */
+       if (sc->use_sg) {
+               pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
+                           sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction));
+       } else if (sc->request_bufflen) {
+               scPrivate       *my_priv;
+
+               my_priv = (scPrivate *) &sc->SCp;
+               pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
+                          sc->request_bufflen,
+                          scsi_to_pci_dma_dir(sc->sc_data_direction));
+       }
+
+       hd->ScsiLookup[req_idx] = NULL;
+
+#ifndef MPT_SCSI_USE_NEW_EH
+       sc->host_scribble = NULL;
+#endif
+
+        MPT_HOST_LOCK(flags);
+       sc->scsi_done(sc);              /* Issue the command callback */
+        MPT_HOST_UNLOCK(flags);
+
+       /* Free Chain buffers */
+       mptscsih_freeChainBuffers(hd, req_idx);
+
+       return 1;
+}
+
+#ifndef MPT_SCSI_USE_NEW_EH    /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     search_taskQ - Search SCSI task mgmt request queue for specific
+ *     request type.
+ *     @remove: (Boolean) Should request be removed if found?
+ *     @sc: Pointer to Scsi_Cmnd structure
+ *     @task_type: Task type to search for
+ *
+ *     Returns pointer to MPT request frame if found, or %NULL if request
+ *     was not found.
+ */
+static MPT_FRAME_HDR *
+search_taskQ(int remove, Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, u8 task_type)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       unsigned long flags;
+       int count = 0;
+       int list_sz;
+
+       dprintk((KERN_INFO MYNAM ": search_taskQ(%d,sc=%p,%d) called\n",
+                       remove, sc, task_type));
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       list_sz = hd->taskQcnt;
+       if (! Q_IS_EMPTY(&hd->taskQ)) {
+               mf = hd->taskQ.head;
+               do {
+                       count++;
+                       if (mf->u.frame.linkage.argp1 == sc &&
+                           mf->u.frame.linkage.arg1 == task_type) {
+                               if (remove) {
+                                       Q_DEL_ITEM(&mf->u.frame.linkage);
+                                       hd->taskQcnt--;
+                                       atomic_dec(&mpt_taskQdepth);
+
+                                       /* Don't save mf into nextmf because
+                                        * exit after command has been deleted.
+                                        */
+
+                                       /* Place the MF back on the FreeQ */
+                                       Q_ADD_TAIL(&hd->ioc->FreeQ,
+                                               &mf->u.frame.linkage,
+                                               MPT_FRAME_HDR);
+#ifdef MFCNT
+                                       hd->ioc->mfcnt--;
+#endif
+                               }
+                               break;
+                       }
+               } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
+               if (mf == (MPT_FRAME_HDR*)&hd->taskQ) {
+                       mf = NULL;
+               }
+       }
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       if (list_sz) {
+               dprintk((KERN_INFO "  Results=%p (%sFOUND%s)!\n",
+                                  mf,
+                                  mf ? "" : "NOT_",
+                                  (mf && remove) ? "+REMOVED" : "" ));
+               dprintk((KERN_INFO "  (searched thru %d of %d items on taskQ)\n",
+                                  count,
+                                  list_sz ));
+       }
+
+       return mf;
+}
+
+/*
+ *     clean_taskQ - Clean the  SCSI task mgmt request for
+ *                     this SCSI host instance.
+ *     @hd: MPT_SCSI_HOST pointer
+ *
+ *     Returns: None.
+ */
+static void
+clean_taskQ(MPT_SCSI_HOST *hd)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       MPT_FRAME_HDR *nextmf = NULL;
+       MPT_ADAPTER *ioc = hd->ioc;
+       unsigned long flags;
+
+       dprintk((KERN_INFO MYNAM ": clean_taskQ called\n"));
+
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       if (! Q_IS_EMPTY(&hd->taskQ)) {
+               mf = hd->taskQ.head;
+               do {
+                       Q_DEL_ITEM(&mf->u.frame.linkage);
+                       hd->taskQcnt--;
+                       atomic_dec(&mpt_taskQdepth);
+
+                       nextmf = mf->u.frame.linkage.forw;
+
+                       /* Place the MF back on the FreeQ */
+                       Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage,
+                               MPT_FRAME_HDR);
+#ifdef MFCNT
+                       hd->ioc->mfcnt--;
+#endif
+               } while ((mf = nextmf) != (MPT_FRAME_HDR*)&hd->taskQ);
+       }
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+       return;
+}
+
+/*
+ *     search_taskQ_for_cmd - Search the  SCSI task mgmt request queue for
+ *                     the specified command. If found, delete
+ *     @hd: MPT_SCSI_HOST pointer
+ *
+ *     Returns: None.
+ */
+static void
+search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd)
+{
+       MPT_FRAME_HDR *mf = NULL;
+       unsigned long flags;
+       int count = 0;
+
+       dprintk((KERN_INFO MYNAM ": search_taskQ_for_cmd(sc=%p) called\n", sc));
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       if (! Q_IS_EMPTY(&hd->taskQ)) {
+               mf = hd->taskQ.head;
+               do {
+                       count++;
+                       if (mf->u.frame.linkage.argp1 == sc) {
+                               Q_DEL_ITEM(&mf->u.frame.linkage);
+                               hd->taskQcnt--;
+                               atomic_dec(&mpt_taskQdepth);
+                               dprintk((KERN_INFO MYNAM
+                                       ": Cmd %p found! Deleting.\n", sc));
+
+                               /* Don't save mf into nextmf because
+                                * exit after command has been deleted.
+                                */
+
+                               /* Place the MF back on the FreeQ */
+                               Q_ADD_TAIL(&hd->ioc->FreeQ,
+                                       &mf->u.frame.linkage,
+                                       MPT_FRAME_HDR);
+#ifdef MFCNT
+                               hd->ioc->mfcnt--;
+#endif
+                               break;
+                       }
+               } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&hd->taskQ);
+       }
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       return;
+}
+
+#endif         /* } MPT_SCSI_USE_NEW_EH */
+
+
+/*
+ * Flush all commands on the doneQ.
+ * Lock Q when deleting/adding members
+ * Lock io_request_lock for OS callback.
+ */
+static void
+flush_doneQ(MPT_SCSI_HOST *hd)
+{
+       MPT_DONE_Q      *buffer;
+       Scsi_Cmnd       *SCpnt;
+       unsigned long    flags;
+
+       /* Flush the doneQ.
+        */
+       dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
+       while (1) {
+               spin_lock_irqsave(&hd->freedoneQlock, flags);
+               if (Q_IS_EMPTY(&hd->doneQ)) {
+                       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       break;
+               }
+
+               buffer = hd->doneQ.head;
+               /* Delete from Q
+                */
+               Q_DEL_ITEM(buffer);
+
+               /* Set the Scsi_Cmnd pointer
+                */
+               SCpnt = (Scsi_Cmnd *) buffer->argp;
+               buffer->argp = NULL;
+
+               /* Add to the freeQ
+                */
+               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+
+               /* Do the OS callback.
+                */
+                MPT_HOST_LOCK(flags);
+               SCpnt->scsi_done(SCpnt);
+                MPT_HOST_UNLOCK(flags);
+       }
+
+       return;
+}
+
+/*
+ * Search the doneQ for a specific command. If found, delete from Q.
+ * Calling function will finish processing.
+ */
+static void
+search_doneQ_for_cmd(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt)
+{
+       unsigned long    flags;
+       MPT_DONE_Q      *buffer;
+
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->doneQ)) {
+               buffer = hd->doneQ.head;
+               do {
+                       Scsi_Cmnd *sc = (Scsi_Cmnd *) buffer->argp;
+                       if (SCpnt == sc) {
+                               Q_DEL_ITEM(buffer);
+                               SCpnt->result = sc->result;
+
+                               /* Set the Scsi_Cmnd pointer
+                                */
+                               buffer->argp = NULL;
+
+                               /* Add to the freeQ
+                                */
+                               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+                               break;
+                       }
+               } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->doneQ);
+       }
+       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       return;
+}
+
+static void
+mptscsih_reset_timeouts (MPT_SCSI_HOST *hd)
+{
+       Scsi_Cmnd       *SCpnt = NULL;
+       int              ii;
+       int              max = hd->ioc->req_depth;
+
+       for (ii= 0; ii < max; ii++) {
+               if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
+                       mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
+                       dtmprintk((MYIOC_s_WARN_FMT "resetting SCpnt=%p timeout + 60HZ",
+                               (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+               }
+       }
+}
+
+/*
+ *     mptscsih_flush_running_cmds - For each command found, search
+ *             Scsi_Host instance taskQ and reply to OS.
+ *             Called only if recovering from a FW reload.
+ *     @hd: Pointer to a SCSI HOST structure
+ *
+ *     Returns: None.
+ *
+ *     Must be called while new I/Os are being queued.
+ */
+static void
+mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
+{
+       Scsi_Cmnd       *SCpnt = NULL;
+       MPT_FRAME_HDR   *mf = NULL;
+       MPT_DONE_Q      *buffer = NULL;
+       int              ii;
+       int              max = hd->ioc->req_depth;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+       unsigned long    flags;
+#endif
+
+       dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
+       for (ii= 0; ii < max; ii++) {
+               if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
+
+                       /* Command found.
+                        */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       /* Search taskQ, if found, delete.
+                        */
+                       search_taskQ_for_cmd(SCpnt, hd);
+#endif
+
+                       /* Search pendingQ, if found,
+                        * delete from Q. If found, do not decrement
+                        * queue_depth, command never posted.
+                        */
+                       if (mptscsih_search_pendingQ(hd, ii) == NULL)
+                               atomic_dec(&queue_depth);
+
+                       /* Null ScsiLookup index
+                        */
+                       hd->ScsiLookup[ii] = NULL;
+
+                       mf = MPT_INDEX_2_MFPTR(hd->ioc, ii);
+                       dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", mf, SCpnt));
+
+                       /* Set status, free OS resources (SG DMA buffers)
+                        * Free driver resources (chain, msg buffers)
+                        */
+                       if (SCpnt->use_sg) {
+                               pci_unmap_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer,
+                                           SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+                       } else if (SCpnt->request_bufflen) {
+                               scPrivate       *my_priv;
+               
+                               my_priv = (scPrivate *) &SCpnt->SCp;
+                               pci_unmap_single(hd->ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
+                                          SCpnt->request_bufflen,
+                                          scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+                       }
+                       SCpnt->result = DID_RESET << 16;
+                       SCpnt->host_scribble = NULL;
+
+                       /* Free Chain buffers */
+                       mptscsih_freeChainBuffers(hd, ii);
+
+                       /* Free Message frames */
+                       mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+
+#if 1
+                       /* Post to doneQ, do not reply until POST phase
+                        * of reset handler....prevents new commands from
+                        * being queued.
+                        */
+                       spin_lock_irqsave(&hd->freedoneQlock, flags);
+                       if (!Q_IS_EMPTY(&hd->freeQ)) {
+                               buffer = hd->freeQ.head;
+                               Q_DEL_ITEM(buffer);
+
+                               /* Set the Scsi_Cmnd pointer
+                                */
+                               buffer->argp = (void *)SCpnt;
+
+                               /* Add to the doneQ
+                                */
+                               Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       } else {
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                               SCpnt->scsi_done(SCpnt);
+                       }
+#else
+                        MPT_HOST_LOCK(flags);
+                       SCpnt->scsi_done(SCpnt);        /* Issue the command callback */
+                        MPT_HOST_UNLOCK(flags);
+#endif
+               }
+       }
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_initChainBuffers - Allocate memory for and initialize
+ *     chain buffers, chain buffer control arrays and spinlock.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @init: If set, initialize the spin lock.
+ */
+static int
+mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init)
+{
+       MPT_FRAME_HDR   *chain;
+       u8              *mem;
+       unsigned long   flags;
+       int             sz, ii, num_chain;
+       int             scale, num_sge;
+
+       /* ReqToChain size must equal the req_depth
+        * index = req_idx
+        */
+       sz = hd->ioc->req_depth * sizeof(int);
+       if (hd->ReqToChain == NULL) {
+               mem = kmalloc(sz, GFP_ATOMIC);
+               if (mem == NULL)
+                       return -1;
+
+               hd->ReqToChain = (int *) mem;
+       } else {
+               mem = (u8 *) hd->ReqToChain;
+       }
+       memset(mem, 0xFF, sz);
+
+
+       /* ChainToChain size must equal the total number
+        * of chain buffers to be allocated.
+        * index = chain_idx
+        *
+        * Calculate the number of chain buffers needed(plus 1) per I/O
+        * then multiply the the maximum number of simultaneous cmds
+        *
+        * num_sge = num sge in request frame + last chain buffer
+        * scale = num sge per chain buffer if no chain element
+        */
+       scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+       if (sizeof(dma_addr_t) == sizeof(u64))
+               num_sge =  scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+       else
+               num_sge =  1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+
+       num_chain = 1;
+       while (hd->max_sge - num_sge > 0) {
+               num_chain++;
+               num_sge += (scale - 1);
+       }
+       num_chain++;
+
+       if ((int) hd->ioc->chip_type > (int) FC929)
+               num_chain *= MPT_SCSI_CAN_QUEUE;
+       else
+               num_chain *= MPT_FC_CAN_QUEUE;
+
+       hd->num_chain = num_chain;
+
+       sz = num_chain * sizeof(int);
+       if (hd->ChainToChain == NULL) {
+               mem = kmalloc(sz, GFP_ATOMIC);
+               if (mem == NULL)
+                       return -1;
+
+               hd->ChainToChain = (int *) mem;
+       } else {
+               mem = (u8 *) hd->ChainToChain;
+       }
+       memset(mem, 0xFF, sz);
+
+       sz = num_chain * hd->ioc->req_sz;
+       if (hd->ChainBuffer == NULL) {
+               /* Allocate free chain buffer pool
+                */
+               mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
+               if (mem == NULL)
+                       return -1;
+
+               hd->ChainBuffer = (u8*)mem;
+       } else {
+               mem = (u8 *) hd->ChainBuffer;
+       }
+       memset(mem, 0, sz);
+
+       dprintk((KERN_INFO "  ChainBuffer    @ %p(%p), sz=%d\n",
+                hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz));
+
+       /* Initialize the free chain Q.
+        */
+       if (init) {
+               spin_lock_init(&hd->FreeChainQlock);
+       }
+
+       spin_lock_irqsave (&hd->FreeChainQlock, flags);
+       Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR);
+
+       /* Post the chain buffers to the FreeChainQ.
+        */
+       mem = (u8 *)hd->ChainBuffer;
+       for (ii=0; ii < num_chain; ii++) {
+               chain = (MPT_FRAME_HDR *) mem;
+               Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
+               mem += hd->ioc->req_sz;
+       }
+       spin_unlock_irqrestore(&hd->FreeChainQlock, flags);
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Hack! It might be nice to report if a device is returning QUEUE_FULL
+ *  but maybe not each and every time...
+ */
+static long last_queue_full = 0;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_report_queue_full - Report QUEUE_FULL status returned
+ *     from a SCSI target device.
+ *     @sc: Pointer to Scsi_Cmnd structure
+ *     @pScsiReply: Pointer to SCSIIOReply_t
+ *     @pScsiReq: Pointer to original SCSI request
+ *
+ *     This routine periodically reports QUEUE_FULL status returned from a
+ *     SCSI target device.  It reports this to the console via kernel
+ *     printk() API call, not more than once every 10 seconds.
+ */
+static void
+mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq)
+{
+       long time = jiffies;
+
+       if (time - last_queue_full > 10 * HZ) {
+               char *ioc_str = "ioc?";
+
+               if (sc->host != NULL && sc->host->hostdata != NULL)
+                       ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name;
+               printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+                               ioc_str, 0, sc->target, sc->lun);
+               last_queue_full = time;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int BeenHereDoneThat = 0;
+static char *info_kbuf = NULL;
+
+/*  SCSI host fops start here...  */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with
+ *     linux scsi mid-layer.
+ *     @tpnt: Pointer to Scsi_Host_Template structure
+ *
+ *     (linux Scsi_Host_Template.detect routine)
+ *
+ *     Returns number of SCSI host adapters that were successfully
+ *     registered with the linux scsi mid-layer via the scsi_register()
+ *     API call.
+ */
+int
+mptscsih_detect(Scsi_Host_Template *tpnt)
+{
+       struct Scsi_Host        *sh = NULL;
+       MPT_SCSI_HOST           *hd = NULL;
+       MPT_ADAPTER             *this;
+       MPT_DONE_Q              *freedoneQ;
+       unsigned long            flags;
+       int                      sz, ii;
+       int                      numSGE = 0;
+       int                      scale;
+       int                      ioc_cap;
+       u8                      *mem;
+
+       if (! BeenHereDoneThat++) {
+            /*show_mptmod_ver(my_NAME, my_VERSION);*/
+
+               ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);
+               ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);
+               ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER);
+
+#ifndef MPT_SCSI_USE_NEW_EH
+               spin_lock_init(&mytaskQ_lock);
+#endif
+
+               if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {
+                       dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));
+               } else {
+                       /* FIXME! */
+               }
+
+               if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {
+                       dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+               } else {
+                       /* FIXME! */
+               }
+       }
+       dprintk((KERN_INFO MYNAM ": mptscsih_detect()\n"));
+
+#ifdef MODULE
+       /* Evaluate the command line arguments, if any */
+       if (mptscsih)
+               mptscsih_setup(mptscsih);
+#endif
+#ifndef MPT_SCSI_USE_NEW_EH
+       atomic_set(&mpt_taskQdepth, 0);
+#endif
+
+       this = mpt_adapter_find_first();
+       while (this != NULL) {
+               /* 20010202 -sralston
+                *  Added sanity check on readiness of the MPT adapter.
+                */
+               if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+                       printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
+                                       this->name);
+                       continue;
+               }
+
+               if (!this->active) {
+                       printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
+                                       this->name);
+                       continue;
+               }
+
+
+               /*  Sanity check - ensure at least 1 port is INITIATOR capable
+                */
+               ioc_cap = 0;
+               for (ii=0; ii < this->facts.NumberOfPorts; ii++) {
+                       if (this->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)
+                               ioc_cap ++;
+               }
+
+               if (!ioc_cap) {
+                       printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n",
+                                       this->name);
+                       continue;
+               }
+
+/* SAE: No proc! */
+#if defined(CONFIG_PROC_FS)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+               tpnt->proc_dir = &proc_mpt_scsihost;
+#endif
+               tpnt->proc_info = mptscsih_proc_info;
+#endif /* SAE: CONFIG_PROC_FS */
+               sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
+               if (sh != NULL) {
+                       spin_lock_irqsave(&this->FreeQlock, flags);
+                       sh->io_port = 0;
+                       sh->n_io_port = 0;
+                       sh->irq = 0;
+
+                       /* Yikes!  This is important!
+                        * Otherwise, by default, linux
+                        * only scans target IDs 0-7!
+                        * pfactsN->MaxDevices unreliable
+                        * (not supported in early
+                        *      versions of the FW).
+                        * max_id = 1 + actual max id,
+                        * max_lun = 1 + actual last lun,
+                        *      see hosts.h :o(
+                        */
+                       if ((int)this->chip_type > (int)FC929)
+                               sh->max_id = MPT_MAX_SCSI_DEVICES;
+                       else {
+                               /* For FC, increase the queue depth
+                                * from MPT_SCSI_CAN_QUEUE (31)
+                                * to MPT_FC_CAN_QUEUE (63).
+                                */
+                               sh->can_queue = MPT_FC_CAN_QUEUE;
+                               sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+                       }
+                       sh->max_lun = MPT_LAST_LUN + 1;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+                       sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+#endif
+/* SAE: The logic of this one just baffles me, should be && defined (I think)... */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && defined CONFIG_HIGHIO
+                       sh->highmem_io = 1;
+#endif
+                       /* MPI uses {port, bus, id, lun}, but logically maps
+                        * devices on different ports to different buses, i.e.,
+                        * bus 1 may be the 2nd bus on port 0 or the 1st bus on port 1.
+                        * Map bus to channel, ignore port number in SCSI....
+                        *      hd->port = 0;
+                        * If max_channel > 0, need to adjust mem alloc, free, DV
+                        * and all access to VirtDev
+                        */
+                       sh->max_channel = 0;
+                       sh->this_id = this->pfacts[0].PortSCSIID;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
+                       /* OS entry to allow host drivers to force
+                        * a queue depth on a per device basis.
+                        */
+                       sh->select_queue_depths = mptscsih_select_queue_depths;
+#endif
+                       /* Required entry.
+                        */
+                       sh->unique_id = this->id;
+
+                       /* Verify that we won't exceed the maximum
+                        * number of chain buffers
+                        * We can optimize:  ZZ = req_sz/sizeof(SGE)
+                        * For 32bit SGE's:
+                        *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+                        *               + (req_sz - 64)/sizeof(SGE)
+                        * A slightly different algorithm is required for
+                        * 64bit SGEs.
+                        */
+                       scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+                       if (sizeof(dma_addr_t) == sizeof(u64)) {
+                               numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+                                       (this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+                       } else {
+                               numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+                                       (this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+                       }
+
+                       if (numSGE < sh->sg_tablesize) {
+                               /* Reset this value */
+                               dprintk((MYIOC_s_INFO_FMT
+                                        "Resetting sg_tablesize to %d from %d\n",
+                                        this->name, numSGE, sh->sg_tablesize));
+                               sh->sg_tablesize = numSGE;
+                       }
+
+                       /* Set the pci device pointer in Scsi_Host structure.
+                        */
+                       scsi_set_pci_device(sh, this->pcidev);
+
+                       spin_unlock_irqrestore(&this->FreeQlock, flags);
+
+                       hd = (MPT_SCSI_HOST *) sh->hostdata;
+                       hd->ioc = this;
+                       hd->max_sge = sh->sg_tablesize;
+
+                       if ((int)this->chip_type > (int)FC929)
+                               hd->is_spi = 1;
+
+                       if (DmpService &&
+                           (this->chip_type == FC919 || this->chip_type == FC929))
+                               hd->is_multipath = 1;
+
+                       /* SCSI needs Scsi_Cmnd lookup table!
+                        * (with size equal to req_depth*PtrSz!)
+                        */
+                       sz = hd->ioc->req_depth * sizeof(void *);
+                       mem = kmalloc(sz, GFP_ATOMIC);
+                       if (mem == NULL)
+                               goto done;
+
+                       memset(mem, 0, sz);
+                       hd->ScsiLookup = (struct scsi_cmnd **) mem;
+
+                       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+                                this->name, hd->ScsiLookup, sz));
+
+                       if (mptscsih_initChainBuffers(hd, 1) < 0)
+                               goto done;
+
+                       /* Allocate memory for free and doneQ's
+                        */
+                       sz = sh->can_queue * sizeof(MPT_DONE_Q);
+                       mem = kmalloc(sz, GFP_ATOMIC);
+                       if (mem == NULL)
+                               goto done;
+
+                       memset(mem, 0xFF, sz);
+                       hd->memQ = mem;
+
+                       /* Initialize the free, done and pending Qs.
+                        */
+                       Q_INIT(&hd->freeQ, MPT_DONE_Q);
+                       Q_INIT(&hd->doneQ, MPT_DONE_Q);
+                       Q_INIT(&hd->pendingQ, MPT_DONE_Q);
+                       spin_lock_init(&hd->freedoneQlock);
+
+                       mem = hd->memQ;
+                       for (ii=0; ii < sh->can_queue; ii++) {
+                               freedoneQ = (MPT_DONE_Q *) mem;
+                               Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
+                               mem += sizeof(MPT_DONE_Q);
+                       }
+
+                       /* Initialize this Scsi_Host
+                        * internal task Q.
+                        */
+                       Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
+                       hd->taskQcnt = 0;
+
+                       /* Allocate memory for the device structures.
+                        * A non-Null pointer at an offset
+                        * indicates a device exists.
+                        * max_id = 1 + maximum id (hosts.h)
+                        */
+                       sz = sh->max_id * sizeof(void *);
+                       mem = kmalloc(sz, GFP_ATOMIC);
+                       if (mem == NULL)
+                               goto done;
+
+                       memset(mem, 0, sz);
+                       hd->Targets = (VirtDevice **) mem;
+
+                       dprintk((KERN_INFO "  Targets @ %p, sz=%d\n", hd->Targets, sz));
+
+
+                       /* Clear the TM flags
+                        */
+                       hd->tmPending = 0;
+#ifdef MPT_SCSI_USE_NEW_EH
+                       hd->tmState = TM_STATE_NONE;
+#endif
+                       hd->resetPending = 0;
+                       hd->abortSCpnt = NULL;
+                       hd->tmPtr = NULL;
+                       hd->numTMrequests = 0;
+
+                       /* Clear the pointer used to store
+                        * single-threaded commands, i.e., those
+                        * issued during a bus scan, dv and
+                        * configuration pages.
+                        */
+                       hd->cmdPtr = NULL;
+
+                       /* Attach the SCSI Host to the IOC structure
+                        */
+                       this->sh = sh;
+
+                       /* Initialize this SCSI Hosts' timers
+                        * To use, set the timer expires field
+                        * and add_timer
+                        */
+                       init_timer(&hd->timer);
+                       hd->timer.data = (unsigned long) hd;
+                       hd->timer.function = mptscsih_timer_expired;
+
+                       init_timer(&hd->TMtimer);
+                       hd->TMtimer.data = (unsigned long) hd;
+                       hd->TMtimer.function = mptscsih_taskmgmt_timeout;
+                       hd->qtag_tick = jiffies;
+
+                       /* Moved Earlier Pam D */
+                       /* this->sh = sh;       */
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+                       hd->ioc->timeout_hard = 0;
+                       hd->ioc->timeout_delta = 30 * HZ;
+                       hd->ioc->timeout_maxcnt = 0;
+                       hd->ioc->timeout_cnt = 0;
+                       for (ii=0; ii < 8; ii++)
+                               foo_to[ii] = NULL;
+#endif
+
+                       if (hd->is_spi) {
+                               /* Update with the driver setup
+                                * values.
+                                */
+                               if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)
+                                       hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;
+                               if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)
+                                       hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac;
+
+                               if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
+                                       hd->ioc->spi_data.maxSyncOffset = 0;
+
+                               hd->negoNvram = 0;
+#ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+                               hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+#endif
+                               if (driver_setup.dv == 0)
+                                       hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+
+                               hd->ioc->spi_data.forceDv = 0;
+                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+                                       hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
+       
+                               if (hd->negoNvram == 0) {
+                                       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+                                               hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE;
+                               }
+
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "dv %x width %x factor %x \n",
+                                       hd->ioc->name, driver_setup.dv,
+                                       driver_setup.max_width,
+                                       driver_setup.min_sync_fac));
+                       }
+
+                       mpt_scsi_hosts++;
+
+               }
+               else {
+                       /* SAE: Nice to know if this is failing */
+                       printk(KERN_WARNING MYNAM ": failed scsi_register\n");
+               }       
+
+               this = mpt_adapter_find_next(this);
+       }
+
+done:
+       if (mpt_scsi_hosts > 0) {
+/* SAE: */
+#if XENO_KILLED
+               register_reboot_notifier(&mptscsih_notifier);
+#endif
+       }
+       else {
+               mpt_reset_deregister(ScsiDoneCtx);
+               dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+
+               mpt_event_deregister(ScsiDoneCtx);
+               dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+
+               mpt_deregister(ScsiScanDvCtx);
+               mpt_deregister(ScsiTaskCtx);
+               mpt_deregister(ScsiDoneCtx);
+
+               if (info_kbuf != NULL)
+                       kfree(info_kbuf);
+       }
+
+       return mpt_scsi_hosts;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_release - Unregister SCSI host from linux scsi mid-layer
+ *     @host: Pointer to Scsi_Host structure
+ *
+ *     (linux Scsi_Host_Template.release routine)
+ *     This routine releases all resources associated with the SCSI host
+ *     adapter.
+ *
+ *     Returns 0 for success.
+ */
+int
+mptscsih_release(struct Scsi_Host *host)
+{
+       MPT_SCSI_HOST   *hd;
+       int              count;
+       unsigned long    flags;
+
+       hd = (MPT_SCSI_HOST *) host->hostdata;
+
+#ifndef MPT_SCSI_USE_NEW_EH
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_release = 1;
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+#endif
+
+       count = 10 * HZ;
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       if (mytaskQ_bh_active) {
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+               dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n"));
+               clean_taskQ(hd);
+
+               while(mytaskQ_bh_active && --count) {
+/* SAE: */
+#ifdef XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+               }
+       } else {
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+       }
+       if (!count)
+               printk(KERN_ERR MYNAM ": ERROR - TaskMgmt thread still active!\n");
+
+#endif
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+       /* Check DV thread active */
+       count = 10 * HZ;
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       if (dvtaskQ_active) {
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+               while(dvtaskQ_active && --count) {
+/* SAE: */
+#ifdef XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(1);
+#else
+                       mdelay(1);
+#endif
+               }
+       } else {
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+       }
+       if (!count)
+               printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+       else
+               printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
+#endif
+#endif
+
+/* SAE: */
+#if XENO_KILLED
+       unregister_reboot_notifier(&mptscsih_notifier);
+#endif
+
+       if (hd != NULL) {
+               int sz1, sz2, sz3, sztarget=0;
+               int szr2chain = 0;
+               int szc2chain = 0;
+               int szchain = 0;
+               int szQ = 0;
+
+               /* Synchronize disk caches
+                */
+               (void) mptscsih_synchronize_cache(hd, 0);
+
+               sz1 = sz2 = sz3 = 0;
+
+               if (hd->ScsiLookup != NULL) {
+                       sz1 = hd->ioc->req_depth * sizeof(void *);
+                       kfree(hd->ScsiLookup);
+                       hd->ScsiLookup = NULL;
+               }
+
+               if (hd->ReqToChain != NULL) {
+                       szr2chain = hd->ioc->req_depth * sizeof(int);
+                       kfree(hd->ReqToChain);
+                       hd->ReqToChain = NULL;
+               }
+
+               if (hd->ChainToChain != NULL) {
+                       szc2chain = hd->num_chain * sizeof(int);
+                       kfree(hd->ChainToChain);
+                       hd->ChainToChain = NULL;
+               }
+
+               if (hd->ChainBuffer != NULL) {
+                       sz2 = hd->num_chain * hd->ioc->req_sz;
+                       szchain = szr2chain + szc2chain + sz2;
+
+                       pci_free_consistent(hd->ioc->pcidev, sz2,
+                                   hd->ChainBuffer, hd->ChainBufferDMA);
+                       hd->ChainBuffer = NULL;
+               }
+
+               if (hd->memQ != NULL) {
+                       szQ = host->can_queue * sizeof(MPT_DONE_Q);
+                       kfree(hd->memQ);
+                       hd->memQ = NULL;
+               }
+
+               if (hd->Targets != NULL) {
+                       int max, ii;
+
+                       /*
+                        * Free any target structures that were allocated.
+                        */
+                       if (hd->is_spi) {
+                               max = MPT_MAX_SCSI_DEVICES;
+                       } else {
+                               max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+                       }
+                       for (ii=0; ii < max; ii++) {
+                               if (hd->Targets[ii]) {
+                                       kfree(hd->Targets[ii]);
+                                       hd->Targets[ii] = NULL;
+                                       sztarget += sizeof(VirtDevice);
+                               }
+                       }
+
+                       /*
+                        * Free pointer array.
+                        */
+                       sz3 = max * sizeof(void *);
+                       kfree(hd->Targets);
+                       hd->Targets = NULL;
+               }
+
+               dprintk((MYIOC_s_INFO_FMT "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
+                               hd->ioc->name, sz1, szchain, sz3, sztarget));
+               dprintk(("Free'd done and free Q (%d) memory\n", szQ));
+       }
+       /* NULL the Scsi_Host pointer
+        */
+       hd->ioc->sh = NULL;
+       scsi_unregister(host);
+
+       if (mpt_scsi_hosts) {
+               if (--mpt_scsi_hosts == 0) {
+                       mpt_reset_deregister(ScsiDoneCtx);
+                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
+
+                       mpt_event_deregister(ScsiDoneCtx);
+                       dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n"));
+
+                       mpt_deregister(ScsiScanDvCtx);
+                       mpt_deregister(ScsiTaskCtx);
+                       mpt_deregister(ScsiDoneCtx);
+
+                       if (info_kbuf != NULL)
+                               kfree(info_kbuf);
+               }
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_halt - Process the reboot notification
+ *     @nb: Pointer to a struct notifier_block (ignored)
+ *     @event: event (SYS_HALT, SYS_RESTART, SYS_POWER_OFF)
+ *     @buf: Pointer to a data buffer (ignored)
+ *
+ *     This routine called if a system shutdown or reboot is to occur.
+ *
+ *     Return NOTIFY_DONE if this is something other than a reboot message.
+ *             NOTIFY_OK if this is a reboot message.
+ */
+static int
+mptscsih_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+       MPT_ADAPTER *ioc = NULL;
+       MPT_SCSI_HOST *hd = NULL;
+
+       /* Ignore all messages other than reboot message
+        */
+       if ((event != SYS_RESTART) && (event != SYS_HALT)
+               && (event != SYS_POWER_OFF))
+               return (NOTIFY_DONE);
+
+       for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+               /* Flush the cache of this adapter
+                */
+               if (ioc->sh) {
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                       if (hd) {
+                               mptscsih_synchronize_cache(hd, 0);
+                       }
+               }
+       }
+
+/* SAE: Gone */
+#if XENO_KILLED 
+       unregister_reboot_notifier(&mptscsih_notifier);
+#endif
+       return NOTIFY_OK;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_info - Return information about MPT adapter
+ *     @SChost: Pointer to Scsi_Host structure
+ *
+ *     (linux Scsi_Host_Template.info routine)
+ *
+ *     Returns pointer to buffer where information was written.
+ */
+const char *
+mptscsih_info(struct Scsi_Host *SChost)
+{
+       MPT_SCSI_HOST *h = NULL;
+       int size = 0;
+
+       if (info_kbuf == NULL)
+               if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL)
+                       return info_kbuf;
+
+       h = (MPT_SCSI_HOST *)SChost->hostdata;
+       info_kbuf[0] = '\0';
+       if (h) {
+               mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0, 0);
+               info_kbuf[size-1] = '\0';
+       }
+
+       return info_kbuf;
+}
+
+struct info_str {
+       char *buffer;
+       int   length;
+       int   offset;
+       int   pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+       if (info->pos + len > info->length)
+               len = info->length - info->pos;
+
+       if (info->pos + len < info->offset) {
+               info->pos += len;
+               return;
+       }
+
+       if (info->pos < info->offset) {
+               data += (info->offset - info->pos);
+               len  -= (info->offset - info->pos);
+       }
+
+       if (len > 0) {
+                memcpy(info->buffer + info->pos, data, len);
+                info->pos += len;
+       }
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+       va_list args;
+       char buf[81];
+       int len;
+
+       va_start(args, fmt);
+       len = vsprintf(buf, fmt, args);
+       va_end(args);
+
+       copy_mem_info(info, buf, len);
+       return len;
+}
+
+/* SAE: For some reason off_t is not in any of the types.. */
+#ifndef off_t
+#define off_t int
+#endif
+
+static int mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
+{
+       struct info_str info;
+
+       info.buffer     = pbuf;
+       info.length     = len;
+       info.offset     = offset;
+       info.pos        = 0;
+
+       copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
+       copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
+       copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
+       copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
+
+       return ((info.pos > info.offset) ? info.pos - info.offset : 0);
+}
+
+#ifndef MPTSCSIH_DBG_TIMEOUT
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len)
+{
+       /* Not yet implemented */
+       return len;
+}
+#else
+#define is_digit(c)    ((c) >= '0' && (c) <= '9')
+#define digit_to_bin(c)        ((c) - '0')
+#define is_space(c)    ((c) == ' ' || (c) == '\t')
+
+#define UC_DBG_TIMEOUT         0x01
+#define UC_DBG_HARDRESET       0x02
+
+static int skip_spaces(char *ptr, int len)
+{
+       int cnt, c;
+
+       for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
+
+       return (len - cnt);
+}
+
+static int get_int_arg(char *ptr, int len, ulong *pv)
+{
+       int cnt, c;
+       ulong   v;
+       for (v =  0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) {
+               v = (v * 10) + digit_to_bin(c);
+       }
+
+       if (pv)
+               *pv = v;
+
+       return (len - cnt);
+}
+
+
+static int is_keyword(char *ptr, int len, char *verb)
+{
+       int verb_len = strlen(verb);
+
+       if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+               return verb_len;
+       else
+               return 0;
+}
+
+#define SKIP_SPACES(min_spaces)                                                \
+       if ((arg_len = skip_spaces(ptr,len)) < (min_spaces))            \
+               return -EINVAL;                                         \
+       ptr += arg_len;                                                 \
+       len -= arg_len;
+
+#define GET_INT_ARG(v)                                                 \
+       if (!(arg_len = get_int_arg(ptr,len, &(v))))                    \
+               return -EINVAL;                                         \
+       ptr += arg_len;                                                 \
+       len -= arg_len;
+
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length)
+{
+       char *ptr = buffer;
+       char btmp[24];  /* REMOVE */
+       int arg_len;
+       int len = length;
+       int cmd;
+       ulong number = 1;
+       ulong delta = 10;
+
+       if ((len > 0) && (ptr[len -1] == '\n'))
+               --len;
+
+       if (len < 22) {
+               strncpy(btmp, buffer, len);
+               btmp[len+1]='\0';
+       } else {
+               strncpy(btmp, buffer, 22);
+               btmp[23]='\0';
+       }
+       printk("user_command:  ioc %d, buffer %s, length %d\n",
+                       ioc->id, btmp, length);
+
+       if ((arg_len = is_keyword(ptr, len, "timeout")) != 0)
+               cmd = UC_DBG_TIMEOUT;
+       else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0)
+               cmd = UC_DBG_HARDRESET;
+       else
+               return -EINVAL;
+
+       ptr += arg_len;
+       len -= arg_len;
+
+       switch(cmd) {
+               case UC_DBG_TIMEOUT:
+                       SKIP_SPACES(1);
+                       GET_INT_ARG(number);
+                       SKIP_SPACES(1);
+                       GET_INT_ARG(delta);
+                       break;
+       }
+
+       printk("user_command: cnt=%ld delta=%ld\n", number, delta);
+
+       if (len)
+               return -EINVAL;
+       else {
+               if (cmd == UC_DBG_HARDRESET) {
+                       ioc->timeout_hard = 1;
+               } else if (cmd == UC_DBG_TIMEOUT) {
+                       /* process this command ...
+                        */
+                       ioc->timeout_maxcnt = 0;
+                       ioc->timeout_delta = delta < 2 ? 2 : delta;
+                       ioc->timeout_cnt = 0;
+                       ioc->timeout_maxcnt = number < 8 ? number: 8;
+               }
+       }
+       /* Not yet implemented */
+       return length;
+}
+#endif
+
+/* SAE: No proc */
+#if defined(CONFIG_PROC_FS)
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_proc_info - Return information about MPT adapter
+ *
+ *     (linux Scsi_Host_Template.info routine)
+ *
+ *     buffer: if write, user data; if read, buffer for user
+ *     length: if write, return length;
+ *     offset: if write, 0; if read, the current offset into the buffer from
+ *             the previous read.
+ *     hostno: scsi host number
+ *     func:   if write = 1; if read = 0
+ */
+int mptscsih_proc_info(char *buffer, char **start, off_t offset,
+                       int length, int hostno, int func)
+{
+       MPT_ADAPTER     *ioc = NULL;
+       MPT_SCSI_HOST   *hd = NULL;
+       int size = 0;
+
+       dprintk(("Called mptscsih_proc_info: hostno=%d, func=%d\n", hostno, func));
+       dprintk(("buffer %p, start=%p (%p) offset=%ld length = %d\n",
+                       buffer, start, *start, offset, length));
+
+       for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+               if ((ioc->sh) && (ioc->sh->host_no == hostno)) {
+                       hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+                       break;
+               }
+       }
+       if ((ioc == NULL) || (ioc->sh == NULL) || (hd == NULL))
+               return 0;
+
+       if (func) {
+               size = mptscsih_user_command(ioc, buffer, length);
+       } else {
+               if (start)
+                       *start = buffer;
+
+               size = mptscsih_host_info(ioc, buffer, offset, length);
+       }
+
+       return size;
+}
+
+#endif /* SAE: CONFIG_PROC_FS */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+       static int max_qd = 1;
+#if 0
+static int index_log[128];
+static int index_ent = 0;
+static __inline__ void ADD_INDEX_LOG(int req_ent)
+{
+       int i = index_ent++;
+
+       index_log[i & (128 - 1)] = req_ent;
+}
+#else
+#define ADD_INDEX_LOG(req_ent) do { } while(0)
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
+ *     @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx)
+ *     @id: IOC id number
+ *     @mf: Pointer to message frame
+ *
+ *     Handles the call to mptbase for posting request and queue depth
+ *     tracking.
+ *
+ *     Returns none.
+ */
+static inline void
+mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf)
+{
+       /* Main banana... */
+       atomic_inc(&queue_depth);
+       if (atomic_read(&queue_depth) > max_qd) {
+               max_qd = atomic_read(&queue_depth);
+               dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd));
+       }
+
+       mpt_put_msg_frame(context, id, mf);
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
+ *     @SCpnt: Pointer to Scsi_Cmnd structure
+ *     @done: Pointer SCSI mid-layer IO completion function
+ *
+ *     (linux Scsi_Host_Template.queuecommand routine)
+ *     This is the primary SCSI IO start routine.  Create a MPI SCSIIORequest
+ *     from a linux Scsi_Cmnd request and send it to the IOC.
+ *
+ *     Returns 0. (rtn value discarded by linux scsi mid-layer)
+ */
+int
+mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       SCSIIORequest_t         *pScsiReq;
+       VirtDevice              *pTarget;
+       MPT_DONE_Q              *buffer = NULL;
+       unsigned long            flags;
+       int      target;
+       int      lun;
+       int      datadir;
+       u32      datalen;
+       u32      scsictl;
+       u32      scsidir;
+       u32      cmd_len;
+       int      my_idx;
+       int      ii;
+       int      rc;
+       int      did_errcode;
+       int      issueCmd;
+
+       did_errcode = 0;
+       hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata;
+       target = SCpnt->target;
+       lun = SCpnt->lun;
+       SCpnt->scsi_done = done;
+
+       pTarget = hd->Targets[target];
+
+       dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
+                       (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+
+       if (hd->resetPending) {
+               /* Prevent new commands from being issued
+                * while reloading the FW. Reset timer to 60 seconds,
+                * as the FW can take some time to come ready.
+                * For New EH, cmds on doneQ posted to FW.
+                */
+               did_errcode = 1;
+               mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
+               dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
+                       (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+               goto did_error;
+       }
+
+       /*
+        *  Put together a MPT SCSI request...
+        */
+       if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {
+               dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+                               hd->ioc->name));
+               did_errcode = 2;
+               goto did_error;
+       }
+
+       pScsiReq = (SCSIIORequest_t *) mf;
+
+       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+
+       ADD_INDEX_LOG(my_idx);
+
+       /*
+        *  The scsi layer should be handling this stuff
+        *  (In 2.3.x it does -DaveM)
+        */
+
+       /*  BUG FIX!  19991030 -sralston
+        *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!
+        *    Seems we may receive a buffer (datalen>0) even when there
+        *    will be no data transfer!  GRRRRR...
+        */
+       datadir = mptscsih_io_direction(SCpnt);
+       if (datadir == SCSI_DATA_READ) {
+               datalen = SCpnt->request_bufflen;
+               scsidir = MPI_SCSIIO_CONTROL_READ;      /* DATA IN  (host<--ioc<--dev) */
+       } else if (datadir == SCSI_DATA_WRITE) {
+               datalen = SCpnt->request_bufflen;
+               scsidir = MPI_SCSIIO_CONTROL_WRITE;     /* DATA OUT (host-->ioc-->dev) */
+       } else {
+               datalen = 0;
+               scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;
+       }
+
+       /* Default to untagged. Once a target structure has been allocated,
+        * use the Inquiry data to determine if device supports tagged.
+        */
+       if (   pTarget
+           && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+           && (SCpnt->device->tagged_supported)) {
+               scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
+       } else {
+               scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED;
+       }
+
+       /* Use the above information to set up the message frame
+        */
+       pScsiReq->TargetID = (u8) target;
+       pScsiReq->Bus = (u8) SCpnt->channel;
+       pScsiReq->ChainOffset = 0;
+       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       pScsiReq->CDBLength = SCpnt->cmd_len;
+       pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+       pScsiReq->Reserved = 0;
+       pScsiReq->MsgFlags = mpt_msg_flags();
+       pScsiReq->LUN[0] = 0;
+       pScsiReq->LUN[1] = lun;
+       pScsiReq->LUN[2] = 0;
+       pScsiReq->LUN[3] = 0;
+       pScsiReq->LUN[4] = 0;
+       pScsiReq->LUN[5] = 0;
+       pScsiReq->LUN[6] = 0;
+       pScsiReq->LUN[7] = 0;
+       pScsiReq->Control = cpu_to_le32(scsictl);
+
+       /*
+        *  Write SCSI CDB into the message
+        *  Should write from cmd_len up to 16, but skip for performance reasons.
+        */
+       cmd_len = SCpnt->cmd_len;
+       for (ii=0; ii < cmd_len; ii++)
+               pScsiReq->CDB[ii] = SCpnt->cmnd[ii];
+
+       for (ii=cmd_len; ii < 16; ii++)
+               pScsiReq->CDB[ii] = 0;
+
+       /* DataLength */
+       pScsiReq->DataLength = cpu_to_le32(datalen);
+
+       /* SenseBuffer low address */
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+                                          + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+
+       /* Now add the SG list
+        * Always have a SGE even if null length.
+        */
+       rc = SUCCESS;
+       if (datalen == 0) {
+               /* Add a NULL SGE */
+               mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,
+                       (dma_addr_t) -1);
+       } else {
+               /* Add a 32 or 64 bit SGE */
+               rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);
+       }
+
+
+       if (rc == SUCCESS) {
+               hd->ScsiLookup[my_idx] = SCpnt;
+               SCpnt->host_scribble = NULL;
+
+               /* SCSI specific processing */
+               issueCmd = 1;
+               if (hd->is_spi) {
+                       int dvStatus = hd->ioc->spi_data.dvStatus[target];
+
+                       if (dvStatus || hd->ioc->spi_data.forceDv) {
+
+                               /* Write SDP1 on this I/O to this target */
+                               if (dvStatus & MPT_SCSICFG_NEGOTIATE) {
+                                       mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);
+                                       dvStatus &= ~MPT_SCSICFG_NEGOTIATE;
+                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+                               } else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {
+                                       mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);
+                                       dvStatus &= ~MPT_SCSICFG_BLK_NEGO;
+                                       hd->ioc->spi_data.dvStatus[target] =  dvStatus;
+                               }
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+                               if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
+                                       (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
+                                       unsigned long lflags;
+                                       /* Schedule DV if necessary */
+                                       spin_lock_irqsave(&dvtaskQ_lock, lflags);
+                                       if (!dvtaskQ_active) {
+                                               dvtaskQ_active = 1;
+                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                               MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
+
+                                               SCHEDULE_TASK(&mptscsih_dvTask);
+                                       } else {
+                                               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                       }
+                                       hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
+                               }
+
+                               /* Trying to do DV to this target, extend timeout.
+                                * Wait to issue intil flag is clear
+                                */
+                               if (dvStatus & MPT_SCSICFG_DV_PENDING) {
+                                       mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
+                                       issueCmd = 0;
+                               }
+
+                               /* Set the DV flags.
+                                */
+                               if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
+                                       mptscsih_set_dvflags(hd, pScsiReq);
+#endif
+                       }
+               }
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+               if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) {
+                       foo_to[hd->ioc->timeout_cnt] = SCpnt;
+                       hd->ioc->timeout_cnt++;
+                       //mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta);
+                       issueCmd = 0;
+                       printk(MYIOC_s_WARN_FMT
+                               "to pendingQ: (sc=%p, mf=%p, time=%ld)\n",
+                               hd->ioc->name, SCpnt, mf, jiffies);
+               }
+#endif
+
+               if (issueCmd) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+                                       hd->ioc->name, SCpnt, mf, my_idx));
+               } else {
+                       ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",
+                                       hd->ioc->name, SCpnt, my_idx));
+                       /* Place this command on the pendingQ if possible */
+                       spin_lock_irqsave(&hd->freedoneQlock, flags);
+                       if (!Q_IS_EMPTY(&hd->freeQ)) {
+                               buffer = hd->freeQ.head;
+                               Q_DEL_ITEM(buffer);
+
+                               /* Save the mf pointer
+                                */
+                               buffer->argp = (void *)mf;
+
+                               /* Add to the pendingQ
+                                */
+                               Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       } else {
+                               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                               SCpnt->result = (DID_BUS_BUSY << 16);
+                               SCpnt->scsi_done(SCpnt);
+                       }
+               }
+       } else {
+               mptscsih_freeChainBuffers(hd, my_idx);
+               mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
+               did_errcode = 3;
+               goto did_error;
+       }
+       
+       return 0;
+
+did_error:
+       dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",
+                       hd->ioc->name, did_errcode, SCpnt));
+       /* Just wish OS to issue a retry */
+       SCpnt->result = (DID_BUS_BUSY << 16);
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->freeQ)) {
+               dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n",
+                       (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+               buffer = hd->freeQ.head;
+               Q_DEL_ITEM(buffer);
+
+               /* Set the Scsi_Cmnd pointer
+                */
+               buffer->argp = (void *)SCpnt;
+
+               /* Add to the doneQ
+                */
+               Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       } else {
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+               SCpnt->scsi_done(SCpnt);
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_freeChainBuffers - Function to free chain buffers associated
+ *     with a SCSI IO request
+ *     @hd: Pointer to the MPT_SCSI_HOST instance
+ *     @req_idx: Index of the SCSI IO request frame.
+ *
+ *     Called if SG chain buffer allocation fails and mptscsih callbacks.
+ *     No return.
+ */
+static void
+mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx)
+{
+       MPT_FRAME_HDR *chain = NULL;
+       unsigned long flags;
+       int chain_idx;
+       int next;
+
+       /* Get the first chain index and reset
+        * tracker state.
+        */
+       chain_idx = hd->ReqToChain[req_idx];
+       hd->ReqToChain[req_idx] = MPT_HOST_NO_CHAIN;
+
+       while (chain_idx != MPT_HOST_NO_CHAIN) {
+
+               /* Save the next chain buffer index */
+               next = hd->ChainToChain[chain_idx];
+
+               /* Free this chain buffer and reset
+                * tracker
+                */
+               hd->ChainToChain[chain_idx] = MPT_HOST_NO_CHAIN;
+
+               chain = (MPT_FRAME_HDR *) (hd->ChainBuffer
+                                       + (chain_idx * hd->ioc->req_sz));
+               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               Q_ADD_TAIL(&hd->FreeChainQ.head,
+                                       &chain->u.frame.linkage, MPT_FRAME_HDR);
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+               dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
+                               hd->ioc->name, chain_idx));
+
+               /* handle next */
+               chain_idx = next;
+       }
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     Reset Handling
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_TMHandler - Generic handler for SCSI Task Management.
+ *     Fall through to mpt_HardResetHandler if: not operational, too many
+ *     failed TM requests or handshake failure.
+ *
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @type: Task Management type
+ *     @target: Logical Target ID for reset (if appropriate)
+ *     @lun: Logical Unit for reset (if appropriate)
+ *     @ctx2abort: Context for the task to be aborted (if appropriate)
+ *     @sleepFlag: If set, use udelay instead of schedule in handshake code.
+ *
+ *     Remark: Currently invoked from a non-interrupt thread (_bh).
+ *
+ *     Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
+ *     will be active.
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ */
+static int
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
+{
+       MPT_ADAPTER     *ioc = NULL;
+       int              rc = -1;
+       int              doTask = 1;
+       u32              ioc_raw_state;
+       unsigned long    flags;
+
+       /* If FW is being reloaded currently, return success to
+        * the calling function.
+        */
+       if (hd == NULL)
+               return 0;
+
+       ioc = hd->ioc;
+       if (ioc == NULL) {
+               printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
+               return FAILED;
+       }
+       dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
+
+       // SJR - CHECKME - Can we avoid this here?
+       // (mpt_HardResetHandler has this check...)
+       spin_lock_irqsave(&ioc->diagLock, flags);
+       if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
+               spin_unlock_irqrestore(&ioc->diagLock, flags);
+               return FAILED;
+       }
+       spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+       /* Do not do a Task Management if there are
+        * too many failed TMs on this adapter.
+        */
+       if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM)
+               doTask = 0;
+
+#ifdef MPT_SCSI_USE_NEW_EH
+       /*  Wait a fixed amount of time for the TM pending flag to be cleared.
+        *  If we time out and not bus reset, then we return a FAILED status to the caller.
+        *  The call to mptscsih_tm_pending_wait() will set the pending flag if we are
+        *  successful. Otherwise, reload the FW.
+        */
+       if (mptscsih_tm_pending_wait(hd) == FAILED) {
+               if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+                       nehprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: "
+                          "Timed out waiting for last TM (%d) to complete! \n",
+                          hd->ioc->name, hd->tmPending));
+                       return FAILED;
+               } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
+                       nehprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: "
+                          "Timed out waiting for last TM (%d) to complete! \n",
+                          hd->ioc->name, hd->tmPending));
+                       return FAILED;
+               } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+                       nehprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: "
+                          "Timed out waiting for last TM (%d) to complete! \n",
+                          hd->ioc->name, hd->tmPending));
+                       if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
+                               return FAILED;
+                               
+                       doTask = 0;
+               }
+       } else {
+               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               hd->tmPending |=  (1 << type);
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+       }
+#endif
+
+       /* Is operational?
+        */
+       ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
+
+#ifdef MPT_DEBUG_RESET
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
+               printk(MYIOC_s_WARN_FMT
+                       "TM Handler: IOC Not operational(0x%x)!\n",
+                       hd->ioc->name, ioc_raw_state);
+       }
+#endif
+
+       if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
+                               && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
+
+               /* Isse the Task Mgmt request.
+                */
+               if (hd->hard_resets < -1)
+                       hd->hard_resets++;
+               rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, sleepFlag);
+               if (rc) {
+                       printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
+               } else {
+                       dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
+               }
+       }
+#ifdef MPTSCSIH_DBG_TIMEOUT
+       if (hd->ioc->timeout_hard)
+               rc = 1;
+#endif
+
+       /* Only fall through to the HRH if this is a bus reset
+        */
+       if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
+               ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
+               dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+                        hd->ioc->name));
+               rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
+       }
+
+       dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
+#ifndef MPT_SCSI_USE_NEW_EH
+       dtmprintk((MYIOC_s_INFO_FMT "TMHandler: _bh_handler state (%d) taskQ count (%d)\n",
+               ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+#endif
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_IssueTaskMgmt - Generic send Task Management function.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @type: Task Management type
+ *     @target: Logical Target ID for reset (if appropriate)
+ *     @lun: Logical Unit for reset (if appropriate)
+ *     @ctx2abort: Context for the task to be aborted (if appropriate)
+ *     @sleepFlag: If set, use udelay instead of schedule in handshake code.
+ *
+ *     Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ *     or a non-interrupt thread.  In the former, must not call schedule().
+ *
+ *     Not all fields are meaningfull for all task types.
+ *
+ *     Returns 0 for SUCCESS, -999 for "no msg frames",
+ *     else other non-zero value returned.
+ */
+static int
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+       int              ii;
+       int              retval;
+
+       /* Return Fail to calling function if no message frames available.
+        */
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+               dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+                               hd->ioc->name));
+               //return FAILED;
+               return -999;
+       }
+       dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+                       hd->ioc->name, mf));
+
+       /* Format the Request
+        */
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       pScsiTm->TargetID = target;
+       pScsiTm->Bus = channel;
+       pScsiTm->ChainOffset = 0;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+
+       pScsiTm->Reserved = 0;
+       pScsiTm->TaskType = type;
+       pScsiTm->Reserved1 = 0;
+       pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
+                           ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
+
+       for (ii= 0; ii < 8; ii++) {
+               pScsiTm->LUN[ii] = 0;
+       }
+       pScsiTm->LUN[1] = lun;
+
+       for (ii=0; ii < 7; ii++)
+               pScsiTm->Reserved2[ii] = 0;
+
+       pScsiTm->TaskMsgContext = ctx2abort;
+       dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt, ctx2abort (0x%08x), type (%d)\n",
+                       hd->ioc->name, ctx2abort, type));
+
+       /* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake
+               mpt_put_msg_frame(hd->ioc->id, mf);
+       * Save the MF pointer in case the request times out.
+       */
+       hd->tmPtr = mf;
+       hd->numTMrequests++;
+       hd->TMtimer.expires = jiffies + HZ*20;  /* 20 seconds */
+       add_timer(&hd->TMtimer);
+
+       if ((retval = mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id,
+                               sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, sleepFlag))
+       != 0) {
+               dtmprintk((MYIOC_s_WARN_FMT "_send_handshake FAILED!"
+                       " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, hd->ioc, mf));
+               hd->numTMrequests--;
+               hd->tmPtr = NULL;
+               del_timer(&hd->TMtimer);
+               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+       }
+
+       return retval;
+}
+
+#ifdef MPT_SCSI_USE_NEW_EH             /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *     (linux Scsi_Host_Template.eh_abort_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_abort(Scsi_Cmnd * SCpnt)
+{
+       MPT_SCSI_HOST   *hd;
+       MPT_FRAME_HDR   *mf;
+       u32              ctx2abort;
+       int              scpnt_idx;
+
+       /* If we can't locate our host adapter structure, return FAILED status.
+        */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               nehprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
+                          "Can't locate host! (sc=%p)\n",
+                          SCpnt));
+               return FAILED;
+       }
+
+       if (hd->resetPending)
+               return FAILED;
+
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n",
+              hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+
+       if (hd->timeouts < -1)
+               hd->timeouts++;
+
+       /* Find this command
+        */
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup. If found in
+                * doneQ, delete from Q. Do OS callback.
+                */
+               search_doneQ_for_cmd(hd, SCpnt);
+
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                          "Command not in the active list! (sc=%p)\n",
+                          hd->ioc->name, SCpnt));
+               return SUCCESS;
+       }
+
+       /* If this command is pended, then timeout/hang occurred
+        * during DV. Post command and flush pending Q
+        * and then following up with the reset request.
+        */
+       if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+               mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+               post_pendingQ_commands(hd);
+               nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
+                          "Posting pended cmd! (sc=%p)\n",
+                          hd->ioc->name, SCpnt));
+       }
+
+       /* Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+        * (the IO to be ABORT'd)
+        *
+        * NOTE: Since we do not byteswap MsgContext, we do not
+        *       swap it here either.  It is an opaque cookie to
+        *       the controller, so it does not matter. -DaveM
+        */
+       mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+       ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
+
+       hd->abortSCpnt = SCpnt;
+       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
+                              SCpnt->channel, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
+               < 0) {
+
+               /* The TM request failed and the subsequent FW-reload failed!
+                * Fatal error case.
+                */
+               printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
+                      hd->ioc->name, SCpnt);
+
+               /* We must clear our pending flag before clearing our state.
+                */
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+
+               return FAILED;
+       }
+       return FAILED;
+
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_dev_reset - Perform a SCSI TARGET_RESET!  new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *     (linux Scsi_Host_Template.eh_dev_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_dev_reset(Scsi_Cmnd * SCpnt)
+{
+       MPT_SCSI_HOST   *hd;
+
+       /* If we can't locate our host adapter structure, return FAILED status.
+        */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+               nehprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
+                          "Can't locate host! (sc=%p)\n",
+                          SCpnt));
+               return FAILED;
+       }
+
+       if (hd->resetPending)
+               return FAILED;
+
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n",
+              hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+
+       /* Unsupported for SCSI. Supported for FCP
+        */
+       if (hd->is_spi)
+               return FAILED;
+
+       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+                              SCpnt->channel, SCpnt->target, 0, 0, NO_SLEEP)
+               < 0){
+               /* The TM request failed and the subsequent FW-reload failed!
+                * Fatal error case.
+                */
+               printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
+                               hd->ioc->name, SCpnt);
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+               return FAILED;
+       }
+       return SUCCESS;
+
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_bus_reset - Perform a SCSI BUS_RESET!  new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *     (linux Scsi_Host_Template.eh_bus_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_bus_reset(Scsi_Cmnd * SCpnt)
+{
+       MPT_SCSI_HOST   *hd;
+
+       /* If we can't locate our host adapter structure, return FAILED status.
+        */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+               nehprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
+                          "Can't locate host! (sc=%p)\n",
+                          SCpnt ) );
+               return FAILED;
+       }
+
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n",
+              hd->ioc->name, SCpnt, atomic_read(&queue_depth));
+
+       if (hd->timeouts < -1)
+               hd->timeouts++;
+
+       /* We are now ready to execute the task management request. */
+       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                              SCpnt->channel, 0, 0, 0, NO_SLEEP)
+           < 0){
+
+               /* The TM request failed and the subsequent FW-reload failed!
+                * Fatal error case.
+                */
+               printk(MYIOC_s_WARN_FMT
+                      "Error processing TaskMgmt request (sc=%p)\n",
+                      hd->ioc->name, SCpnt);
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+               return FAILED;
+       }
+
+       return SUCCESS;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_host_reset - Perform a SCSI host adapter RESET!
+ *     new_eh variant
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *
+ *     (linux Scsi_Host_Template.eh_host_reset_handler routine)
+ *
+ *     Returns SUCCESS or FAILED.
+ */
+int
+mptscsih_host_reset(Scsi_Cmnd *SCpnt)
+{
+       MPT_SCSI_HOST *  hd;
+       int              status = SUCCESS;
+
+       /*  If we can't locate the host to reset, then we failed. */
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL){
+               nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+                            "Can't locate host! (sc=%p)\n",
+                            SCpnt ) );
+               return FAILED;
+       }
+
+       printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n",
+              hd->ioc->name, SCpnt);
+       printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
+              hd->ioc->name, atomic_read(&queue_depth));
+
+       /*  If our attempts to reset the host failed, then return a failed
+        *  status.  The host will be taken off line by the SCSI mid-layer.
+        */
+       if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0){
+               status = FAILED;
+       } else {
+               /*  Make sure TM pending is cleared and TM state is set to
+                *  NONE.
+                */
+               hd->tmPending = 0;
+               hd->tmState = TM_STATE_NONE;
+       }
+
+
+       nehprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: "
+                    "Status = %s\n",
+                    (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
+
+       return status;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_tm_pending_wait - wait for pending task management request to
+ *             complete.
+ *     @hd: Pointer to MPT host structure.
+ *
+ *     Returns {SUCCESS,FAILED}.
+ */
+static int
+mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
+{
+       unsigned long  flags;
+       int            loop_count = 2 * 10 * 4;  /* Wait 2 seconds */
+       int            status = FAILED;
+
+       do {
+               spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+               if (hd->tmState == TM_STATE_NONE) {
+                       hd->tmState = TM_STATE_IN_PROGRESS;
+                       hd->tmPending = 1;
+                       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                       status = SUCCESS;
+                       break;
+               }
+               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+               //set_current_state(TASK_INTERRUPTIBLE);
+               //schedule_timeout(HZ/4);
+               mdelay(250);
+       } while (--loop_count);
+
+       return status;
+}
+
+#else          /* MPT_SCSI old EH stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_old_abort - Abort linux Scsi_Cmnd routine
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted
+ *
+ *     (linux Scsi_Host_Template.abort routine)
+ *
+ *     Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}.
+ */
+int
+mptscsih_old_abort(Scsi_Cmnd *SCpnt)
+{
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       struct mpt_work_struct  *ptaskfoo;
+       unsigned long            flags;
+       int                      scpnt_idx;
+
+       printk(KERN_WARNING MYNAM ": OldAbort scheduling ABORT SCSI IO (sc=%p)\n", (void *) SCpnt);
+       printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               printk(KERN_WARNING "  WARNING - OldAbort, NULL hostdata ptr!!\n");
+               SCpnt->result = DID_ERROR << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_ABORT_NOT_RUNNING;
+       }
+
+       if (hd->timeouts < -1)
+               hd->timeouts++;
+
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup.
+                * If found in doneQ, delete from Q.
+                * Do OS callback.
+                */
+               search_doneQ_for_cmd(hd, SCpnt);
+
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_ABORT_SUCCESS;
+       } else {
+               /* If this command is pended, then timeout/hang occurred
+                * during DV. Force bus reset by posting command to F/W
+                * and then following up with the reset request.
+                */
+               if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       post_pendingQ_commands(hd);
+               }
+       }
+
+       /*
+        *  Check to see if there's already an ABORT queued for this guy.
+        */
+       mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+       if (mf != NULL) {
+               dtmprintk((MYIOC_s_INFO_FMT "OldAbort:Abort Task PENDING cmd (%p) taskQ depth (%d)\n",
+                       hd->ioc->name, SCpnt, hd->taskQcnt));
+               return SCSI_ABORT_PENDING;
+       }
+
+       // SJR - CHECKME - Can we avoid this here?
+       // (mpt_HardResetHandler has this check...)
+       /* If IOC is reloading FW, return PENDING.
+        */
+       spin_lock_irqsave(&hd->ioc->diagLock, flags);
+       if (hd->ioc->diagPending) {
+               spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+               return SCSI_ABORT_PENDING;
+       }
+       spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+
+       /* If there are no message frames what should we do?
+        */
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+               printk((KERN_WARNING "  WARNING - OldAbort, no msg frames!!\n"));
+               /* We are out of message frames!
+                * Call the reset handler to do a FW reload.
+                */
+               printk((KERN_WARNING " Reloading Firmware!!\n"));
+               if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+                       printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+               }
+               return SCSI_ABORT_PENDING;
+       }
+
+       /*
+        *  Add ourselves to (end of) taskQ .
+        *  Check to see if our _bh is running.  If NOT, schedule it.
+        */
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+       hd->taskQcnt++;
+       atomic_inc(&mpt_taskQdepth);
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+
+       /* Save the original SCpnt mf pointer
+        */
+       SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
+
+       /* For the time being, force bus reset on any abort
+        * requests for the 1030/1035 FW.
+        */
+       if (hd->is_spi)
+               mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       else
+               mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
+
+       mf->u.frame.linkage.argp1 = SCpnt;
+       mf->u.frame.linkage.argp2 = (void *) hd;
+
+       dtmprintk((MYIOC_s_INFO_FMT "OldAbort:_bh_handler state (%d) taskQ count (%d)\n",
+               hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+       if (! mytaskQ_bh_active) {
+               mytaskQ_bh_active = 1;
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+               ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+               MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
+
+               SCHEDULE_TASK(ptaskfoo);
+       } else  {
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+       }
+
+       return SCSI_ABORT_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_old_reset - Perform a SCSI BUS_RESET!
+ *     @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to
+ *     @reset_flags: (not used?)
+ *
+ *     (linux Scsi_Host_Template.reset routine)
+ *
+ *     Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}.
+ */
+int
+mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+       MPT_SCSI_HOST           *hd;
+       MPT_FRAME_HDR           *mf;
+       struct mpt_work_struct  *ptaskfoo;
+       unsigned long            flags;
+       int                      scpnt_idx;
+
+       printk(KERN_WARNING MYNAM ": OldReset scheduling BUS_RESET (sc=%p)\n", (void *) SCpnt);
+       printk(KERN_WARNING "  IOs outstanding = %d\n", atomic_read(&queue_depth));
+
+       if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) {
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_RESET_SUCCESS;
+       }
+
+       if (hd->timeouts < -1)
+               hd->timeouts++;
+
+       if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+               /* Cmd not found in ScsiLookup.
+                * If found in doneQ, delete from Q.
+                * Do OS callback.
+                */
+               search_doneQ_for_cmd(hd, SCpnt);
+
+               SCpnt->result = DID_RESET << 16;
+               SCpnt->scsi_done(SCpnt);
+               return SCSI_RESET_SUCCESS;
+       } else {
+               /* If this command is pended, then timeout/hang occurred
+                * during DV. Force bus reset by posting command to F/W
+                * and then following up with the reset request.
+                */
+               if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) {
+                       mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+                       post_pendingQ_commands(hd);
+               }
+       }
+
+       /*
+        *  Check to see if there's an ABORT_TASK queued for this guy.
+        *  If so, delete.
+        */
+       search_taskQ(1, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
+
+       /*
+        *  Check to see if there's already a BUS_RESET queued for this guy.
+        */
+       mf = search_taskQ(0, SCpnt, hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS);
+       if (mf != NULL) {
+               dtmprintk((MYIOC_s_INFO_FMT "OldReset:Reset Task PENDING cmd (%p) taskQ depth (%d)\n",
+                       hd->ioc->name, SCpnt, hd->taskQcnt));
+               return SCSI_RESET_PENDING;
+       }
+
+       // SJR - CHECKME - Can we avoid this here?
+       // (mpt_HardResetHandler has this check...)
+       /* If IOC is reloading FW, return PENDING.
+        */
+       spin_lock_irqsave(&hd->ioc->diagLock, flags);
+       if (hd->ioc->diagPending) {
+               spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+               return SCSI_RESET_PENDING;
+       }
+       spin_unlock_irqrestore(&hd->ioc->diagLock, flags);
+
+       if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) {
+               /* We are out of message frames!
+                * Call the reset handler to do a FW reload.
+                */
+               printk((KERN_WARNING " Reloading Firmware!!\n"));
+               if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+                       printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+               }
+               return SCSI_RESET_PENDING;
+       }
+
+       /*
+        *  Add ourselves to (end of) taskQ.
+        *  Check to see if our _bh is running.  If NOT, schedule it.
+        */
+       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+       Q_ADD_TAIL(&hd->taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+       hd->taskQcnt++;
+       atomic_inc(&mpt_taskQdepth);
+       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+
+
+       dtmprintk((MYIOC_s_INFO_FMT "OldReset: _bh_handler state (%d) taskQ count (%d)\n",
+               hd->ioc->name, mytaskQ_bh_active, hd->taskQcnt));
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       /* Save the original SCpnt mf pointer
+        */
+       SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx);
+
+       mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
+       mf->u.frame.linkage.argp1 = SCpnt;
+       mf->u.frame.linkage.argp2 = (void *) hd;
+
+       if (! mytaskQ_bh_active) {
+               mytaskQ_bh_active = 1;
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+               /*
+                *  Oh how cute, no alloc/free/mgmt needed if we use
+                *  (bottom/unused portion of) MPT request frame.
+                */
+               ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+               MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
+
+               SCHEDULE_TASK(ptaskfoo);
+       } else  {
+               spin_unlock_irqrestore(&mytaskQ_lock, flags);
+       }
+       return SCSI_RESET_PENDING;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler
+ *     @sc: (unused)
+ *
+ *     This routine (thread) is active whenever there are any outstanding
+ *     SCSI task management requests for a SCSI host adapter.
+ *     IMPORTANT!  This routine is scheduled therefore should never be
+ *     running in ISR context.  i.e., it's safe to sleep here.
+ */
+void
+mptscsih_taskmgmt_bh(void *sc)
+{
+       MPT_ADAPTER     *ioc;
+       Scsi_Cmnd       *SCpnt;
+       MPT_FRAME_HDR   *mf = NULL;
+       MPT_SCSI_HOST   *hd;
+       u32              ctx2abort = 0;
+       unsigned long    flags;
+       int              scpnt_idx;
+       int              did;
+       u8               task_type;
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       mytaskQ_bh_active = 1;
+       spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+       do {
+/* SAE: Not in kernel thread */
+#ifdef XENO_KILLED
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(HZ/4);
+#else
+               /* SAE: Trying a lower value... 250 -> 100 */
+               mdelay(100);
+#endif
+               did = 0;
+
+               for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+                       if (ioc->sh) {
+                               hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                               if (hd == NULL) {
+                                       printk(KERN_ERR MYNAM
+                                                       ": ERROR - TaskMgmt NULL SCSI Host!"
+                                                       "(ioc=%p, sh=%p hd=%p)\n",
+                                                       (void *) ioc, (void *) ioc->sh, (void *) hd);
+                                       continue;
+                               }
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+                               if (ioc->timeout_hard == 1) {
+                                       mptscsih_TMHandler(hd, 
+                                               MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 
+                                               0, 0, 0, 0, CAN_SLEEP);
+
+                               }
+#endif
+
+                               spin_lock_irqsave(&ioc->FreeQlock, flags);
+                               if (Q_IS_EMPTY(&hd->taskQ)) {
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               /* If we ever find a non-empty queue,
+                                * keep the handler alive
+                                */
+                               did++;
+
+                               /* tmPending is SMP lock-protected */
+                               if (hd->tmPending || hd->tmPtr) {
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+                               hd->tmPending = 1;
+
+                               /* Process this request
+                                */
+                                mf = hd->taskQ.head;
+                               Q_DEL_ITEM(&mf->u.frame.linkage);
+                               hd->taskQcnt--;
+                               atomic_dec(&mpt_taskQdepth);
+                               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+                               SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1;
+                               if (SCpnt == NULL) {
+                                       printk(KERN_ERR MYNAM ": ERROR - TaskMgmt has NULL SCpnt! (mf=%p:sc=%p)\n",
+                                                       (void *) mf, (void *) SCpnt);
+                                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               /* Get the ScsiLookup index pointer
+                                * from the SC pointer.
+                                */
+                               if (!SCpnt->host_scribble || ((MPT_SCSI_HOST *)SCpnt->host->hostdata != hd)) {
+                                       /* The command associated with the
+                                        * abort/reset request must have
+                                        * completed and this is a stale
+                                        * request. We are done.
+                                        * Free the current MF and continue.
+                                        */
+                                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               scpnt_idx = MFPTR_2_MPT_INDEX(hd->ioc, SCpnt->host_scribble);
+                               if (scpnt_idx != SCPNT_TO_LOOKUP_IDX(SCpnt)) {
+                                       /* Error! this should never happen!!
+                                        */
+                                       mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       continue;
+                               }
+
+                               task_type = mf->u.frame.linkage.arg1;
+                               ctx2abort = 0;
+                               if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+                                       MPT_FRAME_HDR   *SCpntMf;
+
+                                       /*
+                                        * Most important!  Set TaskMsgContext to SCpnt's MsgContext!
+                                        * (the IO to be ABORT'd)
+                                        *
+                                        * NOTE: Since we do not byteswap MsgContext, we do not
+                                        *       swap it here either.  It is an opaque cookie to
+                                        *       the controller, so it does not matter. -DaveM
+                                        */
+                                       SCpntMf = (MPT_FRAME_HDR *) SCpnt->host_scribble;
+                                       ctx2abort = SCpntMf->u.frame.hwhdr.msgctxu.MsgContext;
+
+                                       hd->abortSCpnt = SCpnt;
+                                       printk(KERN_WARNING MYNAM ": Attempting ABORT SCSI IO! (mf=%p:sc=%p)\n",
+                                                       (void *) mf, (void *) SCpnt);
+                               }
+
+                               /* The TM handler will allocate a new mf,
+                                * so free the current mf.
+                                */
+                               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                               mf = NULL;
+
+                               if (mptscsih_TMHandler(hd, task_type, SCpnt->channel,
+                                                     SCpnt->target, SCpnt->lun,
+                                                      ctx2abort, CAN_SLEEP) < 0) {
+
+                                       /* The TM request failed and the subsequent FW-reload failed!
+                                        * Fatal error case.
+                                        */
+                                       printk(KERN_WARNING MYNAM
+                                               ": WARNING[1] - IOC error processing TaskMgmt request (sc=%p)\n", (void *) SCpnt);
+
+                                       if (hd->ScsiLookup[scpnt_idx] != NULL) {
+                                               atomic_dec(&queue_depth);
+                                               SCpnt->result = DID_SOFT_ERROR << 16;
+                                                MPT_HOST_LOCK(flags);
+                                               SCpnt->scsi_done(SCpnt);
+                                                MPT_HOST_UNLOCK(flags);
+                                               mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
+                                       }
+                                       spin_lock_irqsave(&ioc->FreeQlock, flags);
+                                       hd->tmPending = 0;
+                                       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+                                       hd->abortSCpnt = NULL;
+                               }
+                       }
+               }
+               if (atomic_read(&mpt_taskQdepth) > 0)
+                       did++;
+
+       } while ( did );
+
+       spin_lock_irqsave(&mytaskQ_lock, flags);
+       mytaskQ_bh_active = 0;
+       spin_unlock_irqrestore(&mytaskQ_lock, flags);
+
+       return;
+}
+#endif         /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to SCSI task mgmt request frame
+ *     @mr: Pointer to SCSI task mgmt reply frame
+ *
+ *     This routine is called from mptbase.c::mpt_interrupt() at the completion
+ *     of any SCSI task management request.
+ *     This routine is registered with the MPT (base) driver at driver
+ *     load/init time via the mpt_register() API call.
+ *
+ *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ */
+static int
+mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       SCSITaskMgmtReply_t     *pScsiTmReply;
+       SCSITaskMgmt_t          *pScsiTmReq;
+       MPT_SCSI_HOST           *hd = NULL;
+       unsigned long            flags;
+       u8                       tmType = 0;
+
+       dtmprintk((MYIOC_s_INFO_FMT "SCSI TaskMgmt completed (mf=%p,r=%p)\n",
+                       ioc->name, mf, mr));
+                       
+       if (ioc->sh) {
+               /* Depending on the thread, a timer is activated for
+                * the TM request.  Delete this timer on completion of TM.
+                * Decrement count of outstanding TM requests.
+                */
+               hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+               if (hd->tmPtr) {
+                       del_timer(&hd->TMtimer);
+               }
+               dtmprintk((MYIOC_s_INFO_FMT "taskQcnt (%d)\n",
+                       ioc->name, hd->taskQcnt));
+       } else {
+               dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
+                       ioc->name));
+               return 1;
+       }
+
+       if (mr == NULL) {
+               dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
+                       ioc->name, mf));
+               return 1;
+       } else {
+               pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
+               pScsiTmReq = (SCSITaskMgmt_t*)mf;
+
+               /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
+               tmType = pScsiTmReq->TaskType;
+
+               dtmprintk((KERN_INFO "  TaskType = %d, TerminationCount=%d\n",
+                               tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
+
+               /* Error?  (anything non-zero?) */
+               if (*(u32 *)&pScsiTmReply->Reserved2[0]) {
+                       u16      iocstatus;
+
+                       iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+                       dtmprintk((KERN_INFO "  SCSI TaskMgmt (%d) - Oops!\n", tmType));
+                       dtmprintk((KERN_INFO "  IOCStatus = %04xh\n", iocstatus));
+                       dtmprintk((KERN_INFO "  IOCLogInfo = %08xh\n",
+                                le32_to_cpu(pScsiTmReply->IOCLogInfo)));
+
+                       /* clear flags and continue.
+                        */
+                       if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
+                               hd->abortSCpnt = NULL;
+
+                       /* If an internal command is present
+                        * or the TM failed - reload the FW.
+                        * FC FW may respond FAILED to an ABORT
+                        */
+                       if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+                               if ((hd->cmdPtr) ||
+                                   (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
+                                       if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+                                               printk((KERN_WARNING
+                                                       " Firmware Reload FAILED!!\n"));
+                                       }
+                               }
+                       }
+               } else {
+                       dtmprintk((KERN_INFO "  SCSI TaskMgmt SUCCESS!\n"));
+
+#ifndef MPT_SCSI_USE_NEW_EH
+                       if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+                               /* clean taskQ - remove tasks associated with
+                                * completed commands.
+                                */
+                               clean_taskQ(hd);
+                       } else if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+                               /* If taskQ contains another request
+                                * for this SCpnt, delete this request.
+                                */
+                               search_taskQ_for_cmd(hd->abortSCpnt, hd);
+                       }
+#endif
+                       hd->numTMrequests--;
+                       hd->abortSCpnt = NULL;
+                       flush_doneQ(hd);
+
+               }
+       }
+
+#ifndef MPT_SCSI_USE_NEW_EH
+       /*
+        *  Signal to _bh thread that we finished.
+        *  This IOC can now process another TM command.
+        */
+       dtmprintk((MYIOC_s_INFO_FMT "taskmgmt_complete: (=%p) done! Num Failed(%d) Task Count (%d)\n",
+                       ioc->name, mf, hd->numTMrequests, hd->taskQcnt));
+#endif
+       hd->tmPtr = NULL;
+       spin_lock_irqsave(&ioc->FreeQlock, flags);
+       hd->tmPending = 0;
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+#ifdef MPT_SCSI_USE_NEW_EH
+       hd->tmState = TM_STATE_NONE;
+#endif
+
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     This is anyones guess quite frankly.
+ */
+int
+mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+{
+       unsigned capacity = disk->capacity;
+       int size;
+
+       size = capacity;
+       ip[0] = 64;                             /* heads                        */
+       ip[1] = 32;                             /* sectors                      */
+       if ((ip[2] = size >> 11) > 1024) {      /* cylinders, test for big disk */
+               ip[0] = 255;                    /* heads                        */
+               ip[1] = 63;                     /* sectors                      */
+               ip[2] = size / (255 * 63);      /* cylinders                    */
+       }
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     OS entry point to adjust the queue_depths on a per-device basis.
+ *     Called once per device the bus scan. Use it to force the queue_depth
+ *     member to 1 if a device does not support Q tags.
+ */
+void
+mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
+{
+       struct scsi_device      *device;
+       VirtDevice              *pTarget;
+       MPT_SCSI_HOST           *hd;
+
+       for (device = sdList; device != NULL; device = device->next) {
+
+               if (device->host != sh)
+                       continue;
+
+               hd = (MPT_SCSI_HOST *) sh->hostdata;
+               if (hd == NULL)
+                       continue;
+
+               if (hd->Targets != NULL) {
+                       pTarget = NULL;
+                       if (device->id > sh->max_id) {
+                               /* error case, should never happen */
+                               device->queue_depth = 1;
+                               continue;
+                       } else {
+                               pTarget = hd->Targets[device->id];
+                       }
+
+                       if (pTarget == NULL) {
+                               /* error case - don't know about this device */
+                               device->queue_depth = 1;
+                       } else if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+                               if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+                                       device->queue_depth = 1;
+                               else if (((pTarget->inq_data[0] & 0x1f) == 0x00)
+                                        && (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)){
+                                       device->queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+                               } else
+                                       device->queue_depth = MPT_SCSI_CMD_PER_DEV_LOW;
+
+                       } else {
+                               /* error case - No Inq. Data */
+                               device->queue_depth = 1;
+                       }
+
+                       if (pTarget != NULL) {
+                               printk(MYIOC_s_INFO_FMT
+                                        "scsi%d: Id=%d Lun=%d: Queue depth=%d\n",
+                                        hd->ioc->name, sh->host_no,
+                                        device->id, device->lun, device->queue_depth);
+
+                               dprintk((MYIOC_s_INFO_FMT
+                                        "Id = %d, sync factor = %x\n",
+                                        hd->ioc->name, pTarget->target_id,
+                                        pTarget->minSyncFactor));
+                       }
+               }
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private routines...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Utility function to copy sense data from the scsi_cmnd buffer
+ * to the FC and SCSI target structures.
+ *
+ */
+static void
+copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
+{
+       VirtDevice      *target;
+       SCSIIORequest_t *pReq;
+       u32              sense_count = le32_to_cpu(pScsiReply->SenseCount);
+       int              index;
+       char             devFoo[96];
+       IO_Info_t        thisIo;
+
+       /* Get target structure
+        */
+       pReq = (SCSIIORequest_t *) mf;
+       index = (int) pReq->TargetID;
+       target = hd->Targets[index];
+       if (hd->is_multipath && sc->device->hostdata)
+               target = (VirtDevice *) sc->device->hostdata;
+
+       if (sense_count) {
+               u8 *sense_data;
+               int req_index;
+
+               /* Copy the sense received into the scsi command block. */
+               req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+               memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
+
+               /* Log SMART data (asc = 0x5D, non-IM case only) if required.
+                */
+               if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
+                       if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) {
+                               int idx;
+                               MPT_ADAPTER *ioc = hd->ioc;
+
+                               idx = ioc->eventContext % ioc->eventLogSize;
+                               ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
+                               ioc->events[idx].eventContext = ioc->eventContext;
+
+                               ioc->events[idx].data[0] = (pReq->LUN[1] << 24) ||
+                                       (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) ||
+                                       (pReq->Bus << 8) || pReq->TargetID;
+
+                               ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
+
+                               ioc->eventContext++;
+                       }
+               }
+
+               /* Print an error report for the user.
+                */
+               thisIo.cdbPtr = sc->cmnd;
+               thisIo.sensePtr = sc->sense_buffer;
+               thisIo.SCSIStatus = pScsiReply->SCSIStatus;
+               thisIo.DoDisplay = 1;
+               if (hd->is_multipath)
+                       sprintf(devFoo, "%d:%d:%d \"%s\"",
+                                       hd->ioc->id,
+                                       pReq->TargetID,
+                                       pReq->LUN[1],
+                                       target->dev_vol_name);
+               else
+                       sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->target, sc->lun);
+               thisIo.DevIDStr = devFoo;
+/* fubar */
+               thisIo.dataPtr = NULL;
+               thisIo.inqPtr = NULL;
+               if (sc->device) {
+                       thisIo.inqPtr = sc->device->vendor-8;   /* FIXME!!! */
+               }
+               (void) mpt_ScsiHost_ErrorReport(&thisIo);
+
+       } else {
+               dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
+                               hd->ioc->name));
+       }
+
+       return;
+}
+
+static u32
+SCPNT_TO_LOOKUP_IDX(Scsi_Cmnd *sc)
+{
+       MPT_SCSI_HOST *hd;
+       int i;
+
+       hd = (MPT_SCSI_HOST *) sc->host->hostdata;
+
+       for (i = 0; i < hd->ioc->req_depth; i++) {
+               if (hd->ScsiLookup[i] == sc) {
+                       return i;
+               }
+       }
+
+       return -1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/* see mptscsih.h */
+
+#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+       static Scsi_Host_Template driver_template = MPT_SCSIHOST;
+#      include "../../scsi/scsi_module.c.inc"
+#endif
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Search the pendingQ for a command with specific index.
+ * If found, delete and return mf pointer
+ * If not found, return NULL
+ */
+static MPT_FRAME_HDR *
+mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx)
+{
+       unsigned long    flags;
+       MPT_DONE_Q      *buffer;
+       MPT_FRAME_HDR   *mf = NULL;
+       MPT_FRAME_HDR   *cmdMfPtr = NULL;
+
+       ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name));
+       cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+       spin_lock_irqsave(&hd->freedoneQlock, flags);
+       if (!Q_IS_EMPTY(&hd->pendingQ)) {
+               buffer = hd->pendingQ.head;
+               do {
+                       mf = (MPT_FRAME_HDR *) buffer->argp;
+                       if (mf == cmdMfPtr) {
+                               Q_DEL_ITEM(buffer);
+
+                               /* clear the arg pointer
+                                */
+                               buffer->argp = NULL;
+
+                               /* Add to the freeQ
+                                */
+                               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+                               break;
+                       }
+                       mf = NULL;
+               } while ((buffer = buffer->forw) != (MPT_DONE_Q *) &hd->pendingQ);
+       }
+       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+       ddvtprintk((" ...return %p\n", mf));
+       return mf;
+}
+
+/* Post all commands on the pendingQ to the FW.
+ * Lock Q when deleting/adding members
+ * Lock io_request_lock for OS callback.
+ */
+static void
+post_pendingQ_commands(MPT_SCSI_HOST *hd)
+{
+       MPT_FRAME_HDR   *mf;
+       MPT_DONE_Q      *buffer;
+       unsigned long    flags;
+
+       /* Flush the pendingQ.
+        */
+       ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name));
+       while (1) {
+               spin_lock_irqsave(&hd->freedoneQlock, flags);
+               if (Q_IS_EMPTY(&hd->pendingQ)) {
+                       spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+                       break;
+               }
+
+               buffer = hd->pendingQ.head;
+               /* Delete from Q
+                */
+               Q_DEL_ITEM(buffer);
+
+               mf = (MPT_FRAME_HDR *) buffer->argp;
+               buffer->argp = NULL;
+
+               /* Add to the freeQ
+                */
+               Q_ADD_TAIL(&hd->freeQ.head, buffer, MPT_DONE_Q);
+               spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+
+               if (!mf) {
+                       /* This should never happen */
+                       printk(MYIOC_s_WARN_FMT "post_pendingQ_commands: mf %p\n", hd->ioc->name, (void *) mf);
+                       continue;
+               }
+
+               mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
+
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+               {
+                       u16              req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+                       Scsi_Cmnd       *sc = hd->ScsiLookup[req_idx];
+                       printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n",
+                                       hd->ioc->name, sc, req_idx, mf);
+               }
+#endif
+       }
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       MPT_SCSI_HOST   *hd = NULL;
+       unsigned long    flags;
+
+       dtmprintk((KERN_WARNING MYNAM
+                       ": IOC %s_reset routed to SCSI host driver!\n",
+                       reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+                       reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+
+       /* If a FW reload request arrives after base installed but
+        * before all scsi hosts have been attached, then an alt_ioc
+        * may have a NULL sh pointer.
+        */
+       if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+               return 0;
+       else
+               hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+       if (reset_phase == MPT_IOC_SETUP_RESET) {
+               dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
+               /* Clean Up:
+                * 1. Set Hard Reset Pending Flag
+                * All new commands go to doneQ
+                */
+               hd->resetPending = 1;
+
+               /* 2. Reset timeouts on all running commands
+                */
+               mptscsih_reset_timeouts (hd);
+
+       } else if (reset_phase == MPT_IOC_PRE_RESET) {
+               dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
+
+               /* 2. Flush running commands
+                *      Clean ScsiLookup (and associated memory)
+                *      AND clean mytaskQ
+                */
+
+               /* 2b. Reply to OS all known outstanding I/O commands.
+                */
+               mptscsih_flush_running_cmds(hd);
+
+               /* 2c. If there was an internal command that
+                * has not completed, configuration or io request,
+                * free these resources.
+                */
+               if (hd->cmdPtr) {
+                       del_timer(&hd->timer);
+                       mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr);
+                       atomic_dec(&queue_depth);
+               }
+
+               /* 2d. If a task management has not completed,
+                * free resources associated with this request.
+                */
+               if (hd->tmPtr) {
+                       del_timer(&hd->TMtimer);
+                       mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr);
+               }
+
+#ifndef MPT_SCSI_USE_NEW_EH
+               /* 2e. Delete all commands on taskQ
+                * Should be superfluous - as this taskQ should
+                * be empty.
+                */
+               clean_taskQ(hd);
+#endif
+               
+#ifdef MPTSCSIH_DBG_TIMEOUT
+               ioc->timeout_hard = 0;
+#endif
+
+               dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
+       } else {
+               ScsiCfgData     *pSpi = NULL;
+
+               dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
+
+               /* Once a FW reload begins, all new OS commands are
+                * redirected to the doneQ w/ a reset status.
+                * Init all control structures.
+                */
+
+               /* ScsiLookup initialization
+                */
+               {
+                       int ii;
+                       for (ii=0; ii < hd->ioc->req_depth; ii++)
+                               hd->ScsiLookup[ii] = NULL;
+               }
+
+               /* 2. Chain Buffer initialization
+                */
+               mptscsih_initChainBuffers(hd, 0);
+
+               /* 3. tmPtr clear
+                */
+               if (hd->tmPtr) {
+                       hd->tmPtr = NULL;
+               }
+
+               /* 4. Renegotiate to all devices, if SCSI
+                */
+               if (hd->is_spi)
+                       mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
+
+               /* 5. Enable new commands to be posted
+                */
+               spin_lock_irqsave(&ioc->FreeQlock, flags);
+               hd->tmPending = 0;
+               spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+               hd->resetPending = 0;
+               hd->numTMrequests = 0;
+#ifdef MPT_SCSI_USE_NEW_EH
+               hd->tmState = TM_STATE_NONE;
+#endif
+
+               /* 6. If there was an internal command,
+                * wake this process up.
+                */
+               if (hd->cmdPtr) {
+                       /*
+                        * Wake up the original calling thread
+                        */
+                       hd->pLocal = &hd->localReply;
+                       hd->pLocal->completion = MPT_SCANDV_DID_RESET;
+                       scandv_wait_done = 1;
+/* SAE: No wait queues */
+#ifdef XENO_KILLED
+                       wake_up(&scandv_waitq);
+#else
+                       mdelay(100);
+#endif
+                       hd->cmdPtr = NULL;
+               }
+
+               /* 7. Flush doneQ
+                */
+               flush_doneQ(hd);
+
+               /* 8. Set flag to force DV and re-read IOC Page 3
+                */
+               if (hd->is_spi) {
+                       pSpi = &ioc->spi_data;
+                       pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+                       ddvtprintk(("Set reload IOC Pg3 Flag\n"));
+               }
+
+               dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
+       }
+
+       return 1;               /* currently means nothing really */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+       MPT_SCSI_HOST *hd;
+       u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+
+       dprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event));
+
+       switch (event) {
+       case MPI_EVENT_UNIT_ATTENTION:                  /* 03 */
+               /* FIXME! */
+               break;
+       case MPI_EVENT_IOC_BUS_RESET:                   /* 04 */
+       case MPI_EVENT_EXT_BUS_RESET:                   /* 05 */
+               hd = NULL;
+               if (ioc->sh) {
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                       if (hd && (hd->is_spi) && (hd->soft_resets < -1))
+                               hd->soft_resets++;
+               }
+               break;
+       case MPI_EVENT_LOGOUT:                          /* 09 */
+               /* FIXME! */
+               break;
+
+               /*
+                *  CHECKME! Don't think we need to do
+                *  anything for these, but...
+                */
+       case MPI_EVENT_RESCAN:                          /* 06 */
+       case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
+       case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
+               /*
+                *  CHECKME!  Falling thru...
+                */
+               break;
+
+       case MPI_EVENT_INTEGRATED_RAID:                 /* 0B */
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+               /* negoNvram set to 0 if DV enabled and to USE_NVRAM if
+                * if DV disabled. Need to check for target mode.
+                */
+               hd = NULL;
+               if (ioc->sh)
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+
+               if (hd && (hd->is_spi) && (hd->negoNvram == 0)) {
+                       ScsiCfgData     *pSpi;
+                       Ioc3PhysDisk_t  *pPDisk;
+                       int              numPDisk;
+                       u8               reason;
+                       u8               physDiskNum;
+                       
+                       reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
+                       if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
+                               /* New or replaced disk.
+                                * Set DV flag and schedule DV.
+                                */
+                               pSpi = &ioc->spi_data;
+                               physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
+                               ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
+                               if (pSpi->pIocPg3) {
+                                       pPDisk =  pSpi->pIocPg3->PhysDisk;
+                                       numPDisk =pSpi->pIocPg3->NumPhysDisks;
+
+                                       while (numPDisk) {
+                                               if (physDiskNum == pPDisk->PhysDiskNum) {
+                                                       pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
+                                                       pSpi->forceDv = MPT_SCSICFG_NEED_DV;
+                                                       ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+                                                       break;
+                                               }
+                                               pPDisk++;
+                                               numPDisk--;
+                                       }
+
+                                       if (numPDisk == 0) {
+                                               /* The physical disk that needs DV was not found
+                                                * in the stored IOC Page 3. The driver must reload
+                                                * this page. DV routine will set the NEED_DV flag for
+                                                * all phys disks that have DV_NOT_DONE set.
+                                                */
+                                               pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+                                               ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
+                                       }
+                               }
+                       }
+               }
+#endif
+
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+               printk("Raid Event RF: ");
+               {
+                       u32 *m = (u32 *)pEvReply;
+                       int ii;
+                       int n = (int)pEvReply->MsgLength;
+                       for (ii=6; ii < n; ii++)
+                               printk(" %08x", le32_to_cpu(m[ii]));
+                       printk("\n");
+               }
+#endif
+               break;
+
+       case MPI_EVENT_NONE:                            /* 00 */
+       case MPI_EVENT_LOG_DATA:                        /* 01 */
+       case MPI_EVENT_STATE_CHANGE:                    /* 02 */
+       case MPI_EVENT_EVENT_CHANGE:                    /* 0A */
+       default:
+               dprintk((KERN_INFO "  Ignoring event (=%02Xh)\n", event));
+               break;
+       }
+
+       return 1;               /* currently means nothing really */
+}
+
+#if 0          /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting.
+ *
+ *     drivers/message/fusion/scsiherr.c
+ */
+
+//extern const char    **mpt_ScsiOpcodesPtr;   /* needed by mptscsih.c */
+//extern ASCQ_Table_t   *mpt_ASCQ_TablePtr;
+//extern int             mpt_ASCQ_TableSz;
+
+#define MYNAM  "mptscsih"
+
+#endif         /* } */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Private data...
+ */
+static ASCQ_Table_t *mptscsih_ASCQ_TablePtr;
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* old symsense.c stuff... */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Private data...
+ * To protect ourselves against those that would pass us bogus pointers
+ */
+static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES]
+    = { 0x1F, 0x00, 0x00, 0x00,
+       0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummySenseData[SCSI_STD_SENSE_BYTES]
+    = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00 };
+static u8 dummyCDB[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static u8 dummyScsiData[16]
+    = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#if 0
+static const char *PeripheralDeviceTypeString[32] = {
+       "Direct-access",                /* 00h */
+       "Sequential-access",            /* 01h */
+       "Printer",                      /* 02h */
+       "Processor",                    /* 03h */
+                       /*"Write-Once-Read-Multiple",*/ /* 04h */
+       "WORM",                         /* 04h */
+       "CD-ROM",                       /* 05h */
+       "Scanner",                      /* 06h */
+       "Optical memory",               /* 07h */
+       "Media Changer",                /* 08h */
+       "Communications",               /* 09h */
+       "(Graphics arts pre-press)",    /* 0Ah */
+       "(Graphics arts pre-press)",    /* 0Bh */
+       "Array controller",             /* 0Ch */
+       "Enclosure services",           /* 0Dh */
+       "Simplified direct-access",     /* 0Eh */
+       "Reserved-0Fh",                 /* 0Fh */
+       "Reserved-10h",                 /* 10h */
+       "Reserved-11h",                 /* 11h */
+       "Reserved-12h",                 /* 12h */
+       "Reserved-13h",                 /* 13h */
+       "Reserved-14h",                 /* 14h */
+       "Reserved-15h",                 /* 15h */
+       "Reserved-16h",                 /* 16h */
+       "Reserved-17h",                 /* 17h */
+       "Reserved-18h",                 /* 18h */
+       "Reserved-19h",                 /* 19h */
+       "Reserved-1Ah",                 /* 1Ah */
+       "Reserved-1Bh",                 /* 1Bh */
+       "Reserved-1Ch",                 /* 1Ch */
+       "Reserved-1Dh",                 /* 1Dh */
+       "Reserved-1Eh",                 /* 1Eh */
+       "Unknown"                       /* 1Fh */
+};
+#endif
+
+static char *ScsiStatusString[] = {
+       "GOOD",                                 /* 00h */
+       NULL,                                   /* 01h */
+       "CHECK CONDITION",                      /* 02h */
+       NULL,                                   /* 03h */
+       "CONDITION MET",                        /* 04h */
+       NULL,                                   /* 05h */
+       NULL,                                   /* 06h */
+       NULL,                                   /* 07h */
+       "BUSY",                                 /* 08h */
+       NULL,                                   /* 09h */
+       NULL,                                   /* 0Ah */
+       NULL,                                   /* 0Bh */
+       NULL,                                   /* 0Ch */
+       NULL,                                   /* 0Dh */
+       NULL,                                   /* 0Eh */
+       NULL,                                   /* 0Fh */
+       "INTERMEDIATE",                         /* 10h */
+       NULL,                                   /* 11h */
+       NULL,                                   /* 12h */
+       NULL,                                   /* 13h */
+       "INTERMEDIATE-CONDITION MET",           /* 14h */
+       NULL,                                   /* 15h */
+       NULL,                                   /* 16h */
+       NULL,                                   /* 17h */
+       "RESERVATION CONFLICT",                 /* 18h */
+       NULL,                                   /* 19h */
+       NULL,                                   /* 1Ah */
+       NULL,                                   /* 1Bh */
+       NULL,                                   /* 1Ch */
+       NULL,                                   /* 1Dh */
+       NULL,                                   /* 1Eh */
+       NULL,                                   /* 1Fh */
+       NULL,                                   /* 20h */
+       NULL,                                   /* 21h */
+       "COMMAND TERMINATED",                   /* 22h */
+       NULL,                                   /* 23h */
+       NULL,                                   /* 24h */
+       NULL,                                   /* 25h */
+       NULL,                                   /* 26h */
+       NULL,                                   /* 27h */
+       "TASK SET FULL",                        /* 28h */
+       NULL,                                   /* 29h */
+       NULL,                                   /* 2Ah */
+       NULL,                                   /* 2Bh */
+       NULL,                                   /* 2Ch */
+       NULL,                                   /* 2Dh */
+       NULL,                                   /* 2Eh */
+       NULL,                                   /* 2Fh */
+       "ACA ACTIVE",                           /* 30h */
+       NULL
+};
+
+static const char *ScsiCommonOpString[] = {
+       "TEST UNIT READY",                      /* 00h */
+       "REZERO UNIT (REWIND)",                 /* 01h */
+       NULL,                                   /* 02h */
+       "REQUEST_SENSE",                        /* 03h */
+       "FORMAT UNIT (MEDIUM)",                 /* 04h */
+       "READ BLOCK LIMITS",                    /* 05h */
+       NULL,                                   /* 06h */
+       "REASSIGN BLOCKS",                      /* 07h */
+       "READ(6)",                              /* 08h */
+       NULL,                                   /* 09h */
+       "WRITE(6)",                             /* 0Ah */
+       "SEEK(6)",                              /* 0Bh */
+       NULL,                                   /* 0Ch */
+       NULL,                                   /* 0Dh */
+       NULL,                                   /* 0Eh */
+       "READ REVERSE",                         /* 0Fh */
+       "WRITE_FILEMARKS",                      /* 10h */
+       "SPACE(6)",                             /* 11h */
+       "INQUIRY",                              /* 12h */
+       NULL
+};
+
+static const char *SenseKeyString[] = {
+       "NO SENSE",                             /* 0h */
+       "RECOVERED ERROR",                      /* 1h */
+       "NOT READY",                            /* 2h */
+       "MEDIUM ERROR",                         /* 3h */
+       "HARDWARE ERROR",                       /* 4h */
+       "ILLEGAL REQUEST",                      /* 5h */
+       "UNIT ATTENTION",                       /* 6h */
+       "DATA PROTECT",                         /* 7h */
+       "BLANK CHECK",                          /* 8h */
+       "VENDOR-SPECIFIC",                      /* 9h */
+       "ABORTED COPY",                         /* Ah */
+       "ABORTED COMMAND",                      /* Bh */
+       "EQUAL (obsolete)",                     /* Ch */
+       "VOLUME OVERFLOW",                      /* Dh */
+       "MISCOMPARE",                           /* Eh */
+       "RESERVED",                             /* Fh */
+       NULL
+};
+
+#define SPECIAL_ASCQ(c,q) \
+       (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70))
+
+#if 0
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set,
+ *                        then print additional information via
+ *                        a call to SDMS_SystemAlert().
+ */
+static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1)
+{
+       u8      *sd;
+       u8       BadValue;
+       u8       SenseKey;
+       int      Offset;
+       int      len = strlen(msg1);
+
+       sd = ioop->sensePtr;
+       if (SD_Additional_Sense_Length(sd) < 8)
+               return;
+
+       SenseKey = SD_Sense_Key(sd);
+
+       if (SD_Sense_Key_Specific_Valid(sd)) {
+               if (SenseKey == SK_ILLEGAL_REQUEST) {
+                       Offset = SD_Bad_Byte(sd);
+                       if (SD_Was_Illegal_Request(sd)) {
+                               BadValue = ioop->cdbPtr[Offset];
+                               len += sprintf(msg1+len, "\n  Illegal CDB value=%02Xh found at CDB ",
+                                               BadValue);
+               } else {
+                       BadValue = ioop->dataPtr[Offset];
+                       len += sprintf(msg1+len, "\n  Illegal DATA value=%02Xh found at DATA ",
+                                       BadValue);
+               }
+               len += sprintf(msg1+len, "byte=%02Xh", Offset);
+               if (SD_SKS_Bit_Pointer_Valid(sd))
+                       len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd));
+               } else if ((SenseKey == SK_RECOVERED_ERROR) ||
+                          (SenseKey == SK_HARDWARE_ERROR) ||
+                          (SenseKey == SK_MEDIUM_ERROR)) {
+                       len += sprintf(msg1+len, "\n  Recovery algorithm Actual_Retry_Count=%02Xh",
+                       SD_Actual_Retry_Count(sd));
+               }
+       }
+}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int dump_cdb(char *foo, unsigned char *cdb)
+{
+       int i, grpCode, cdbLen;
+       int l = 0;
+
+       grpCode = cdb[0] >> 5;
+       if (grpCode < 1)
+               cdbLen = 6;
+       else if (grpCode < 3)
+               cdbLen = 10;
+       else if (grpCode == 5)
+               cdbLen = 12;
+       else
+               cdbLen = 16;
+
+       for (i=0; i < cdbLen; i++)
+               l += sprintf(foo+l, " %02X", cdb[i]);
+
+       return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#if 0
+static int dump_sd(char *foo, unsigned char *sd)
+{
+       int snsLen = 8 + SD_Additional_Sense_Length(sd);
+       int l = 0;
+       int i;
+
+       for (i=0; i < MIN(snsLen,18); i++)
+               l += sprintf(foo+l, " %02X", sd[i]);
+       l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : "");
+
+       return l;
+}
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
+static const char * ascq_set_strings_4max(
+               u8 ASC, u8 ASCQ,
+               const char **s1, const char **s2, const char **s3, const char **s4)
+{
+       static const char *asc_04_part1_string = "LOGICAL UNIT ";
+       static const char *asc_04_part2a_string = "NOT READY, ";
+       static const char *asc_04_part2b_string = "IS ";
+       static const char *asc_04_ascq_NN_part3_strings[] = {   /* ASC ASCQ (hex) */
+         "CAUSE NOT REPORTABLE",                               /* 04 00 */
+         "IN PROCESS OF BECOMING READY",                       /* 04 01 */
+         "INITIALIZING CMD. REQUIRED",                         /* 04 02 */
+         "MANUAL INTERVENTION REQUIRED",                       /* 04 03 */
+         /* Add        " IN PROGRESS" to all the following... */
+         "FORMAT",                                             /* 04 04 */
+         "REBUILD",                                            /* 04 05 */
+         "RECALCULATION",                                      /* 04 06 */
+         "OPERATION",                                          /* 04 07 */
+         "LONG WRITE",                                         /* 04 08 */
+         "SELF-TEST",                                          /* 04 09 */
+         NULL
+       };
+       static char *asc_04_part4_string = " IN PROGRESS";
+
+       static char *asc_29_ascq_NN_strings[] = {               /* ASC ASCQ (hex) */
+         "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED",      /* 29 00 */
+         "POWER ON OCCURRED",                                  /* 29 01 */
+         "SCSI BUS RESET OCCURRED",                            /* 29 02 */
+         "BUS DEVICE RESET FUNCTION OCCURRED",                 /* 29 03 */
+         "DEVICE INTERNAL RESET",                              /* 29 04 */
+         "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED",           /* 29 05 */
+         "TRANSCEIVER MODE CHANGED TO LVD",                    /* 29 06 */
+         NULL
+       };
+       static char *ascq_vendor_uniq = "(Vendor Unique)";
+       static char *ascq_noone = "(no matching ASC/ASCQ description found)";
+       int idx;
+
+       *s1 = *s2 = *s3 = *s4 = "";             /* set'em all to the empty "" string */
+
+       /* CHECKME! Need lock/sem?
+        *  Update and examine for isense module presense.
+        */
+       mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr;
+
+       if (mptscsih_ASCQ_TablePtr == NULL) {
+               /* 2nd chances... */
+               if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) {
+                       *s1 = asc_04_part1_string;
+                       *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string;
+                       *s3 = asc_04_ascq_NN_part3_strings[ASCQ];
+                       /* check for " IN PROGRESS" ones */
+                       if (ASCQ >= 0x04)
+                               *s4 = asc_04_part4_string;
+               } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1))
+                       *s1 = asc_29_ascq_NN_strings[ASCQ];
+               /*
+                *      Else { leave all *s[1-4] values pointing to the empty "" string }
+                */
+               return *s1;
+       }
+
+       /*
+        * Need to check ASC here; if it is "special," then
+        * the ASCQ is variable, and indicates failed component number.
+        * We must treat the ASCQ as a "don't care" while searching the
+        * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
+        * on when we actually need to identify the failed component.
+        */
+       if (SPECIAL_ASCQ(ASC,ASCQ))
+               ASCQ = 0xFF;
+
+       /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */
+       for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++)
+               if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) {
+                       *s1 = mptscsih_ASCQ_TablePtr[idx].Description;
+                       return *s1;
+               }
+
+       if ((ASC >= 0x80) || (ASCQ >= 0x80))
+               *s1 = ascq_vendor_uniq;
+       else
+               *s1 = ascq_noone;
+
+       return *s1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Information Report; desired output format...
+ *---
+SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION)
+  Key=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  CDB: 00 00 00 00 00 00 - TestUnitReady
+ *---
+ */
+/*
+ *  SCSI Error Report; desired output format...
+ *---
+SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
+  SCSI_Status=02h (CHECK CONDITION)
+  Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady
+  SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00
+  SenseKey=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+ *---
+ */
+
+int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop)
+{
+       char             foo[512];
+       char             buf2[32];
+       char            *statstr;
+       const char      *opstr;
+       int              sk             = SD_Sense_Key(ioop->sensePtr);
+       const char      *skstr          = SenseKeyString[sk];
+       unsigned char    asc            = SD_ASC(ioop->sensePtr);
+       unsigned char    ascq           = SD_ASCQ(ioop->sensePtr);
+       int              l;
+
+       /* Change the error logging to only report errors on
+        * read and write commands. Ignore errors on other commands.
+        * Should this be configurable via proc?
+        */
+       switch (ioop->cdbPtr[0]) {
+       case READ_6:
+       case WRITE_6:
+       case READ_10:
+       case WRITE_10:
+       case READ_12:
+       case WRITE_12:
+               break;
+       default:
+               return 0;
+       }
+
+       /*
+        *  More quiet mode.
+        *  Filter out common, repetitive, warning-type errors...  like:
+        *    POWER ON (06,29/00 or 06,29/01),
+        *    SPINNING UP (02,04/01),
+        *    LOGICAL UNIT NOT SUPPORTED (05,25/00), etc.
+        */
+       if (sk == SK_NO_SENSE) {
+               return 0;
+       }
+
+       if (    (sk==SK_UNIT_ATTENTION  && asc==0x29 && (ascq==0x00 || ascq==0x01))
+            || (sk==SK_NOT_READY       && asc==0x04 && (ascq==0x01 || ascq==0x02))
+            || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
+          )
+       {
+               /* Do nothing! */
+               return 0;
+       }
+
+       /* Prevent the system from continually writing to the log
+        * if a medium is not found: 02 3A 00
+        * Changer issues: TUR, Read Capacity, Table of Contents continually
+        */
+       if (sk==SK_NOT_READY && asc==0x3A) {
+               if (ioop->cdbPtr == NULL) {
+                       return 0;
+               } else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) ||
+                       (ioop->cdbPtr[0] == CMD_ReadCapacity) ||
+                       (ioop->cdbPtr[0] == 0x43)) {
+                       return 0;
+               }
+       }
+       if (sk==SK_UNIT_ATTENTION) {
+               if (ioop->cdbPtr == NULL)
+                       return 0;
+               else if (ioop->cdbPtr[0] == CMD_TestUnitReady)
+                       return 0;
+       }
+
+       /*
+        *  Protect ourselves...
+        */
+       if (ioop->cdbPtr == NULL)
+               ioop->cdbPtr = dummyCDB;
+       if (ioop->sensePtr == NULL)
+               ioop->sensePtr = dummySenseData;
+       if (ioop->inqPtr == NULL)
+               ioop->inqPtr = dummyInqData;
+       if (ioop->dataPtr == NULL)
+               ioop->dataPtr = dummyScsiData;
+
+       statstr = NULL;
+       if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) ||
+           ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) {
+               (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus);
+               statstr = buf2;
+       }
+
+       opstr = NULL;
+       if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*))
+               opstr = ScsiCommonOpString[ioop->cdbPtr[0]];
+       else if (mpt_ScsiOpcodesPtr)
+               opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
+
+       l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n",
+                         ioop->DevIDStr,
+                         ioop->SCSIStatus,
+                         statstr);
+       l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh",
+                 sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
+       {
+               const char      *x1, *x2, *x3, *x4;
+               x1 = x2 = x3 = x4 = "";
+               x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4);
+               if (x1 != NULL) {
+                       if (x1[0] != '(')
+                               l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4);
+                       else
+                               l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
+               }
+       }
+       l += sprintf(foo+l, "\n CDB:");
+       l += dump_cdb(foo+l, ioop->cdbPtr);
+       if (opstr)
+               l += sprintf(foo+l, " - \"%s\"", opstr);
+       l += sprintf(foo+l, "\n");
+
+       PrintF(("%s\n", foo));
+
+       return l;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_initTarget - Target, LUN alloc/free functionality.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @bus_id: Bus number (?)
+ *     @target_id: SCSI target id
+ *     @lun: SCSI LUN id
+ *     @data: Pointer to data
+ *     @dlen: Number of INQUIRY bytes
+ *
+ *     NOTE: It's only SAFE to call this routine if data points to
+ *     sane & valid STANDARD INQUIRY data!
+ *
+ *     Allocate and initialize memory for this target.
+ *     Save inquiry data.
+ *
+ *     Returns pointer to VirtDevice structure.
+ */
+static VirtDevice *
+mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen)
+{
+       VirtDevice      *vdev;
+       int              sz;
+
+       dprintk((MYIOC_s_INFO_FMT "initTarget (%d,%d,%d) called, hd=%p\n",
+                       hd->ioc->name, bus_id, target_id, lun, hd));
+
+       if ((vdev = hd->Targets[target_id]) == NULL) {
+               if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) {
+                       printk(MYIOC_s_ERR_FMT "initTarget kmalloc(%d) FAILED!\n",
+                                       hd->ioc->name, (int)sizeof(VirtDevice));
+               } else {
+                       memset(vdev, 0, sizeof(VirtDevice));
+                       rwlock_init(&vdev->VdevLock);
+                       Q_INIT(&vdev->WaitQ, void);
+                       Q_INIT(&vdev->SentQ, void);
+                       Q_INIT(&vdev->DoneQ, void);
+                       vdev->tflags = 0;
+                       vdev->ioc_id = hd->ioc->id;
+                       vdev->target_id = target_id;
+                       vdev->bus_id = bus_id;
+
+                       hd->Targets[target_id] = vdev;
+                       dprintk((KERN_INFO "  *NEW* Target structure (id %d) @ %p\n",
+                                       target_id, vdev));
+               }
+       }
+
+       vdev->raidVolume = 0;
+       if (vdev && hd->is_spi) {
+               if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
+                       vdev->raidVolume = 1;
+                       ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
+               }
+       }
+
+       if (vdev && data) {
+               if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) ||
+               ((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) {
+
+                       /* Copy the inquiry data  - if we haven't yet.
+                       */
+                       sz = MIN(dlen, SCSI_STD_INQUIRY_BYTES);
+
+                       memcpy (vdev->inq_data, data, sz);
+                       vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+
+                       /* Update the target capabilities
+                        */
+                       if (dlen > 56) {
+                               mptscsih_setTargetNegoParms(hd, vdev, data[56]);
+                               vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
+                       } else
+                               mptscsih_setTargetNegoParms(hd, vdev, 0);
+
+                       /* If LUN 0, tape and have not done DV, set the DV flag.
+                        */
+                       if (hd->is_spi && (lun == 0) && ((data[0] & 0x1F) == 0x01)) {
+                               ScsiCfgData *pSpi = &hd->ioc->spi_data;
+                               if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE)
+                                       pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV;
+                       }
+               }
+
+               /* Is LUN supported? If so, upper 3 bits will be 0
+                * in first byte of inquiry data.
+                */
+               if ((*data & 0xe0) == 0)
+                       vdev->luns |= (1 << lun);
+       }
+
+
+       dprintk((KERN_INFO "  target = %p\n", vdev));
+       return vdev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Update the target negotiation parameters based on the
+ *  the Inquiry data, adapter capabilities, and NVRAM settings.
+ *
+ */
+void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
+{
+       ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+       int  id = (int) target->target_id;
+       int  nvram;
+       char canQ = 0;
+       u8 width = MPT_NARROW;
+       u8 factor = MPT_ASYNC;
+       u8 offset = 0;
+       u8 version, nfactor;
+       u8 noQas = 0;
+
+       ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56));
+
+       if (!hd->is_spi) {
+               if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+                       if (target->inq_data[7] & 0x02)
+                               target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+               }
+               return;
+       }
+
+       /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
+        * support. If available, default QAS to off and allow enabling.
+        * If not available, default QAS to on, turn off for non-disks.
+        */
+       if (target->tflags & MPT_TARGET_FLAGS_VALID_56)
+               noQas = 1;
+
+       /* Set flags based on Inquiry data
+        */
+       if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+               if ((target->inq_data[0] & 0x1F) != 0x00)
+                       noQas = 1;
+
+               version = target->inq_data[2] & 0x07;
+               if (version < 2) {
+                       width = 0;
+                       factor = MPT_ULTRA2;
+                       offset = pspi_data->maxSyncOffset;
+               } else {
+                       if (target->inq_data[7] & 0x20) {
+                               width = 1;
+                       }
+
+                       if (target->inq_data[7] & 0x10) {
+                               /* bits 2 & 3 show DT support
+                                */
+                               if ((byte56 & 0x04) == 0)
+                                       factor = MPT_ULTRA2;
+                               else if ((byte56 & 0x03) == 0)
+                                       factor = MPT_ULTRA160;
+                               else
+                                       factor = MPT_ULTRA320;
+
+                               /* If RAID, never disable QAS
+                                * else if non RAID, do not disable
+                                *   QAS if bit 1 is set
+                                * bit 1 QAS support, non-raid only
+                                * bit 0 IU support
+                                */
+                               if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
+                                       noQas = 0;
+
+                               offset = pspi_data->maxSyncOffset;
+                       } else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+               }
+
+               if (target->inq_data[7] & 0x02) {
+                       canQ = 1;
+               }
+
+               /* Update tflags based on NVRAM settings. (SCSI only)
+                */
+               if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                       nvram = pspi_data->nvram[id];
+                       nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+
+                       if (width)
+                               width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+                       if (offset > 0) {
+                               /* Ensure factor is set to the
+                                * maximum of: adapter, nvram, inquiry
+                                */
+                               if (nfactor) {
+                                       if (nfactor < pspi_data->minSyncFactor )
+                                               nfactor = pspi_data->minSyncFactor;
+
+                                       factor = MAX (factor, nfactor);
+                                       if (factor == MPT_ASYNC)
+                                               offset = 0;
+                               } else {
+                                       offset = 0;
+                                       factor = MPT_ASYNC;
+                               }
+                       } else {
+                               factor = MPT_ASYNC;
+                       }
+               }
+
+               /* Make sure data is consistent
+                */
+               if ((!width) && (factor < MPT_ULTRA2)) {
+                       factor = MPT_ULTRA2;
+               }
+
+               /* Save the data to the target structure.
+                */
+               target->minSyncFactor = factor;
+               target->maxOffset = offset;
+               target->maxWidth = width;
+               if (canQ) {
+                       target->tflags |= MPT_TARGET_FLAGS_Q_YES;
+               }
+
+               target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
+
+               /* Disable unused features.
+                */
+               target->negoFlags = pspi_data->noQas;
+               if (!width)
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+               if (!offset)
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+               if (noQas)
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+               /* GEM, processor WORKAROUND
+                */
+               if (((target->inq_data[0] & 0x1F) == 0x03) || ((target->inq_data[0] & 0x1F) > 0x08)){
+                       target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+                       pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
+               }
+
+               /* Disable QAS if mixed configuration case
+                */
+               if ((noQas) && (!pspi_data->noQas) && ((target->inq_data[0] & 0x1F) != 0x03)){
+                       VirtDevice      *vdev;
+                       int ii;
+
+                       ddvtprintk((KERN_INFO "Disabling QAS!\n"));
+                       pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
+                       for (ii = 0; ii < id; ii++) {
+                               vdev = hd->Targets[id];
+                               if (vdev != NULL)
+                                       vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+                       }
+               }
+       }
+
+       return;
+}
+
+/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
+ * Else set the NEED_DV flag after Read Capacity Issued (disks)
+ * or Mode Sense (cdroms).
+ *
+ * Tapes, initTarget will set this flag on completion of Inquiry command.
+ * Called only if DV_NOT_DONE flag is set
+ */
+static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
+{
+       u8 cmd;
+       
+       if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
+               return;
+
+       cmd = pReq->CDB[0];
+
+       if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
+               ScsiCfgData *pSpi = &hd->ioc->spi_data;
+               if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
+                       /* Set NEED_DV for all hidden disks
+                        */
+                       Ioc3PhysDisk_t *pPDisk =  pSpi->pIocPg3->PhysDisk;
+                       int             numPDisk = pSpi->pIocPg3->NumPhysDisks;
+
+                       while (numPDisk) {
+                               pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+                               ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+                               pPDisk++;
+                               numPDisk--;
+                       }
+               }
+               pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV;
+               ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID));
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * If no Target, bus reset on 1st I/O. Set the flag to
+ * prevent any future negotiations to this device.
+ */
+static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id)
+{
+
+       if ((hd->Targets) && (hd->Targets[target_id] == NULL))
+               hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO;
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  SCSI Config Page functionality ...
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_setDevicePage1Flags  - add Requested and Configuration fields flags
+ *     based on width, factor and offset parameters.
+ *     @width: bus width
+ *     @factor: sync factor
+ *     @offset: sync offset
+ *     @requestedPtr: pointer to requested values (updated)
+ *     @configurationPtr: pointer to configuration values (updated)
+ *     @flags: flags to block WDTR or SDTR negotiation
+ *
+ *     Return: None.
+ *
+ *     Remark: Called by writeSDP1 and _dv_params
+ */
+static void
+mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
+{
+       u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
+       u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
+
+       *configurationPtr = 0;
+       *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
+       *requestedPtr |= (offset << 16) | (factor << 8);
+
+       if (width && offset && !nowide && !nosync) {
+               if (factor < MPT_ULTRA160) {
+                       *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
+                       if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
+                               *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
+               } else if (factor < MPT_ULTRA2) {
+                       *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
+               }
+       }
+
+       if (nowide)
+               *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
+
+       if (nosync)
+               *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_writeSDP1  - write SCSI Device Page 1
+ *     @hd: Pointer to a SCSI Host Strucutre
+ *     @portnum: IOC port number
+ *     @target_id: writeSDP1 for single ID
+ *     @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
+ *
+ *     Return: -EFAULT if read of config page header fails
+ *             or 0 if success.
+ *
+ *     Remark: If a target has been found, the settings from the
+ *             target structure are used, else the device is set
+ *             to async/narrow.
+ *
+ *     Remark: Called during init and after a FW reload.
+ *     Remark: We do not wait for a return, write pages sequentially.
+ */
+static int
+mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
+{
+       MPT_ADAPTER             *ioc = hd->ioc;
+       Config_t                *pReq = NULL;
+       SCSIDevicePage1_t       *pData = NULL;
+       VirtDevice              *pTarget = NULL;
+       MPT_FRAME_HDR           *mf;
+       dma_addr_t               dataDma;
+       u16                      req_idx;
+       u32                      frameOffset;
+       u32                      requested, configuration, flagsLength;
+       int                      ii, nvram;
+       int                      id = 0, maxid = 0;
+       u8                       width;
+       u8                       factor;
+       u8                       offset;
+       u8                       bus = 0;
+       u8                       negoFlags;
+       u8                       maxwidth, maxoffset, maxfactor;
+
+
+       if (ioc->spi_data.sdp1length == 0)
+               return 0;
+
+       if (flags & MPT_SCSICFG_ALL_IDS) {
+               id = 0;
+               maxid = ioc->sh->max_id - 1;
+       } else if (ioc->sh) {
+               id = target_id;
+               maxid = MIN(id, ioc->sh->max_id - 1);
+       }
+
+       for (; id <= maxid; id++) {
+
+               if (id == ioc->pfacts[portnum].PortSCSIID)
+                       continue;
+
+               /* Use NVRAM to get adapter and target maximums
+                * Data over-riden by target structure information, if present
+                */
+               maxwidth = ioc->spi_data.maxBusWidth;
+               maxoffset = ioc->spi_data.maxSyncOffset;
+               maxfactor = ioc->spi_data.minSyncFactor;
+               if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                       nvram = ioc->spi_data.nvram[id];
+
+                       if (maxwidth)
+                               maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+                       if (maxoffset > 0) {
+                               maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+                               if (maxfactor == 0) {
+                                       /* Key for async */
+                                       maxfactor = MPT_ASYNC;
+                                       maxoffset = 0;
+                               } else if (maxfactor < ioc->spi_data.minSyncFactor) {
+                                       maxfactor = ioc->spi_data.minSyncFactor;
+                               }
+                       } else
+                               maxfactor = MPT_ASYNC;
+               }
+
+               /* Set the negotiation flags.
+                */
+               negoFlags = ioc->spi_data.noQas;
+               if (!maxwidth)
+                       negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+               if (!maxoffset)
+                       negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+               if (flags & MPT_SCSICFG_USE_NVRAM) {
+                       width = maxwidth;
+                       factor = maxfactor;
+                       offset = maxoffset;
+               } else {
+                       width = 0;
+                       factor = MPT_ASYNC;
+                       offset = 0;
+                       //negoFlags = 0;
+                       //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
+               }
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+               /* Force to async and narrow if DV has not been executed
+                * for this ID
+                */
+               if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
+                       width = 0;
+                       factor = MPT_ASYNC;
+                       offset = 0;
+               }
+#endif
+
+               /* If id is not a raid volume, get the updated
+                * transmission settings from the target structure.
+                */
+               if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
+                       width = pTarget->maxWidth;
+                       factor = pTarget->minSyncFactor;
+                       offset = pTarget->maxOffset;
+                       negoFlags = pTarget->negoFlags;
+                       pTarget = NULL;
+               }
+
+               if (flags & MPT_SCSICFG_BLK_NEGO)
+                       negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
+
+               mptscsih_setDevicePage1Flags(width, factor, offset,
+                                       &requested, &configuration, negoFlags);
+
+               /* Get a MF for this command.
+                */
+               if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) {
+                       dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
+                                               ioc->name));
+                       return -EAGAIN;
+               }
+
+               ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
+                       hd->ioc->name, mf, id, requested, configuration));
+
+
+               /* Set the request and the data pointers.
+                * Request takes: 36 bytes (32 bit SGE)
+                * SCSI Device Page 1 requires 16 bytes
+                * 40 + 16 <= size of SCSI IO Request = 56 bytes
+                * and MF size >= 64 bytes.
+                * Place data at end of MF.
+                */
+               pReq = (Config_t *)mf;
+
+               req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
+
+               pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
+               dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
+
+               /* Complete the request frame (same for all requests).
+                */
+               pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               pReq->Reserved = 0;
+               pReq->ChainOffset = 0;
+               pReq->Function = MPI_FUNCTION_CONFIG;
+               pReq->Reserved1[0] = 0;
+               pReq->Reserved1[1] = 0;
+               pReq->Reserved1[2] = 0;
+               pReq->MsgFlags = 0;
+               for (ii=0; ii < 8; ii++) {
+                       pReq->Reserved2[ii] = 0;
+               }
+               pReq->Header.PageVersion = ioc->spi_data.sdp1version;
+               pReq->Header.PageLength = ioc->spi_data.sdp1length;
+               pReq->Header.PageNumber = 1;
+               pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+               pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
+
+               /* Add a SGE to the config request.
+                */
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
+
+               mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+               /* Set up the common data portion
+                */
+               pData->Header.PageVersion = pReq->Header.PageVersion;
+               pData->Header.PageLength = pReq->Header.PageLength;
+               pData->Header.PageNumber = pReq->Header.PageNumber;
+               pData->Header.PageType = pReq->Header.PageType;
+               pData->RequestedParameters = cpu_to_le32(requested);
+               pData->Reserved = 0;
+               pData->Configuration = cpu_to_le32(configuration);
+
+               dprintk((MYIOC_s_INFO_FMT
+                       "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
+                               ioc->name, id, (id | (bus<<8)),
+                               requested, configuration));
+
+               mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf);
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_taskmgmt_timeout - Call back for timeout on a
+ *     task management request.
+ *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ *
+ */
+static void mptscsih_taskmgmt_timeout(unsigned long data)
+{
+       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+
+       dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_taskmgmt_timeout: "
+                  "TM request timed out!\n", hd->ioc->name));
+
+       /* Delete the timer that triggered this callback.
+        * Remark: del_timer checks to make sure timer is active
+        * before deleting.
+        */
+       del_timer(&hd->TMtimer);
+
+       /* Call the reset handler. Already had a TM request
+        * timeout - so issue a diagnostic reset
+        */
+       if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+               printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+       }
+#ifdef MPT_SCSI_USE_NEW_EH
+       else {
+               /* Because we have reset the IOC, no TM requests can be
+                * pending.  So let's make sure the tmPending flag is reset.
+                */
+               nehprintk((KERN_WARNING MYNAM
+                          ": %s: mptscsih_taskmgmt_timeout\n",
+                          hd->ioc->name));
+               hd->tmPending = 0;
+       }
+#endif
+
+       return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *  Bus Scan and Domain Validation functionality ...
+ */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     mptscsih_scandv_complete - Scan and DV callback routine registered
+ *     to Fustion MPT (base) driver.
+ *
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @mf: Pointer to original MPT request frame
+ *     @mr: Pointer to MPT reply frame (NULL if TurboReply)
+ *
+ *     This routine is called from mpt.c::mpt_interrupt() at the completion
+ *     of any SCSI IO request.
+ *     This routine is registered with the Fusion MPT (base) driver at driver
+ *     load/init time via the mpt_register() API call.
+ *
+ *     Returns 1 indicating alloc'd request frame ptr should be freed.
+ *
+ *     Remark: Sets a completion code and (possibly) saves sense data
+ *     in the IOC member localReply structure.
+ *     Used ONLY for DV and other internal commands.
+ */
+static int
+mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       MPT_SCSI_HOST   *hd;
+       SCSIIORequest_t *pReq;
+       int              completionCode;
+       u16              req_idx;
+
+       if ((mf == NULL) ||
+           (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
+               printk(MYIOC_s_ERR_FMT
+                       "ScanDvComplete, %s req frame ptr! (=%p)\n",
+                               ioc->name, mf?"BAD":"NULL", (void *) mf);
+               goto wakeup;
+       }
+
+       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+       del_timer(&hd->timer);
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       hd->ScsiLookup[req_idx] = NULL;
+       pReq = (SCSIIORequest_t *) mf;
+
+       if (mf != hd->cmdPtr) {
+               printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
+                               hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+       }
+       hd->cmdPtr = NULL;
+
+       ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
+                       hd->ioc->name, mf, mr, req_idx));
+
+       atomic_dec(&queue_depth);
+
+       hd->pLocal = &hd->localReply;
+       hd->pLocal->scsiStatus = 0;
+
+       /* If target struct exists, clear sense valid flag.
+        */
+       if (mr == NULL) {
+               completionCode = MPT_SCANDV_GOOD;
+       } else {
+               SCSIIOReply_t   *pReply;
+               u16              status;
+
+               pReply = (SCSIIOReply_t *) mr;
+
+               status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
+               ddvtprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+                            status, pReply->SCSIState, pReply->SCSIStatus,
+                            le32_to_cpu(pReply->IOCLogInfo)));
+
+               switch(status) {
+
+               case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
+                       completionCode = MPT_SCANDV_SELECTION_TIMEOUT;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
+               case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
+               case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
+                       completionCode = MPT_SCANDV_DID_RESET;
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:          /* 0x0045 */
+               case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
+               case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
+                       if (pReply->Function == MPI_FUNCTION_CONFIG) {
+                               ConfigReply_t *pr = (ConfigReply_t *)mr;
+                               completionCode = MPT_SCANDV_GOOD;
+                               hd->pLocal->header.PageVersion = pr->Header.PageVersion;
+                               hd->pLocal->header.PageLength = pr->Header.PageLength;
+                               hd->pLocal->header.PageNumber = pr->Header.PageNumber;
+                               hd->pLocal->header.PageType = pr->Header.PageType;
+
+                       } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) {
+                               /* If the RAID Volume request is successful,
+                                * return GOOD, else indicate that
+                                * some type of error occurred.
+                                */
+                               MpiRaidActionReply_t    *pr = (MpiRaidActionReply_t *)mr;
+                               if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS)
+                                       completionCode = MPT_SCANDV_GOOD;
+                               else
+                                       completionCode = MPT_SCANDV_SOME_ERROR;
+
+                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+                               u8              *sense_data;
+                               int              sz;
+
+                               /* save sense data in global structure
+                                */
+                               completionCode = MPT_SCANDV_SENSE;
+                               hd->pLocal->scsiStatus = pReply->SCSIStatus;
+                               sense_data = ((u8 *)hd->ioc->sense_buf_pool +
+                                       (req_idx * MPT_SENSE_BUFFER_ALLOC));
+
+                               sz = MIN (pReq->SenseBufferLength,
+                                                       SCSI_STD_SENSE_BYTES);
+                               memcpy(hd->pLocal->sense, sense_data, sz);
+
+                               ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
+                                               sense_data));
+                       } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+                               if (pReq->CDB[0] == CMD_Inquiry)
+                                       completionCode = MPT_SCANDV_ISSUE_SENSE;
+                               else
+                                       completionCode = MPT_SCANDV_DID_RESET;
+                       }
+                       else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
+                               completionCode = MPT_SCANDV_DID_RESET;
+                       else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                               completionCode = MPT_SCANDV_DID_RESET;
+                       else {
+                               /* If no error, this will be equivalent
+                                * to MPT_SCANDV_GOOD
+                                */
+                               completionCode = MPT_SCANDV_GOOD;
+                               hd->pLocal->scsiStatus = pReply->SCSIStatus;
+                       }
+                       break;
+
+               case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:         /* 0x0047 */
+                       if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
+                               completionCode = MPT_SCANDV_DID_RESET;
+                       else
+                               completionCode = MPT_SCANDV_SOME_ERROR;
+                       break;
+
+               default:
+                       completionCode = MPT_SCANDV_SOME_ERROR;
+                       break;
+
+               }       /* switch(status) */
+
+               ddvtprintk((KERN_NOTICE "  completionCode set to %08xh\n",
+                               completionCode));
+       } /* end of address reply case */
+
+       hd->pLocal->completion = completionCode;
+
+       /* MF and RF are freed in mpt_interrupt
+        */
+wakeup:
+       /* Free Chain buffers (will never chain) in scan or dv */
+       //mptscsih_freeChainBuffers(hd, req_idx);
+
+       /*
+        * Wake up the original calling thread
+        */
+       scandv_wait_done = 1;
+/* SAE: No wait queues */
+#ifdef XENO_KILLED
+       wake_up(&scandv_waitq);
+#else
+       mdelay(100);
+#endif
+
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_timer_expired - Call back for timer process.
+ *     Used only for dv functionality.
+ *     @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ *
+ */
+static void mptscsih_timer_expired(unsigned long data)
+{
+       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+#ifndef MPT_SCSI_USE_NEW_EH
+       unsigned long  flags;
+#endif
+
+
+       ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+
+       if (hd->cmdPtr) {
+               MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
+
+               if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
+                       /* Desire to issue a task management request here.
+                        * TM requests MUST be single threaded.
+                        * If old eh code and no TM current, issue request.
+                        * If new eh code, do nothing. Wait for OS cmd timeout
+                        *      for bus reset.
+                        */
+#ifndef MPT_SCSI_USE_NEW_EH
+                       SCSIIORequest_t *pReq = (SCSIIORequest_t *) hd->cmdPtr;
+
+                       spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+                       if (hd->tmPending) {
+                               spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                               return;
+                       } else
+                               hd->tmPending = 1;
+                       spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+                       if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                                                       pReq->Bus, 0, 0, 0, NO_SLEEP) < 0) {
+                               printk(MYIOC_s_WARN_FMT "TM FAILED!\n", hd->ioc->name);
+                       }
+#else
+                       ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
+#endif
+               } else {
+                       /* Perform a FW reload */
+                       if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
+                               printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
+                       }
+               }
+       } else {
+               /* This should NEVER happen */
+               printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
+       }
+
+       /* No more processing.
+        * TM call will generate an interrupt for SCSI TM Management.
+        * The FW will reply to all outstanding commands, callback will finish cleanup.
+        * Hard reset clean-up will free all resources.
+        */
+       ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
+
+       return;
+}
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_do_raid - Format and Issue a RAID volume request message.
+ *     @hd: Pointer to scsi host structure
+ *     @action: What do be done.
+ *     @id: Logical target id.
+ *     @bus: Target locations bus.
+ *
+ *     Returns: < 0 on a fatal error
+ *             0 on success
+ *
+ *     Remark: Wait to return until reply processed by the ISR.
+ */
+static int
+mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
+{
+       MpiRaidActionRequest_t  *pReq;
+       MPT_FRAME_HDR           *mf;
+       int                     in_isr;
+
+       in_isr = in_interrupt();
+       if (in_isr) {
+               dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
+                                       hd->ioc->name));
+               return -EPERM;
+       }
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
+               ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+                                       hd->ioc->name));
+               return -EAGAIN;
+       }
+       pReq = (MpiRaidActionRequest_t *)mf;
+       pReq->Action = action;
+       pReq->Reserved1 = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_RAID_ACTION;
+       pReq->VolumeID = io->id;
+       pReq->VolumeBus = io->bus;
+       pReq->PhysDiskNum = io->physDiskNum;
+       pReq->MsgFlags = 0;
+       pReq->Reserved2 = 0;
+       pReq->ActionDataWord = 0; /* Reserved for this action */
+       //pReq->ActionDataSGE = 0;
+
+       mpt_add_sge((char *)&pReq->ActionDataSGE,
+               MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+       ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
+                       hd->ioc->name, action, io->id));
+
+       hd->pLocal = NULL;
+       hd->timer.expires = jiffies + HZ*2; /* 2 second timeout */
+       scandv_wait_done = 0;
+
+       /* Save cmd pointer, for resource free if timeout or
+        * FW reload occurs
+        */
+       hd->cmdPtr = mf;
+
+       add_timer(&hd->timer);
+       mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+/* SAE: No wait queues */
+#ifdef XENO_KILLED
+       wait_event(scandv_waitq, scandv_wait_done);
+#else
+       /* SAE: Decrease the wait time: 100 -> 1 */
+       while(!scandv_wait_done) {
+               mdelay(1);
+       }       
+#endif
+
+       if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
+               return -1;
+
+       return 0;
+}
+#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_do_cmd - Do internal command.
+ *     @hd: MPT_SCSI_HOST pointer
+ *     @io: INTERNAL_CMD pointer.
+ *
+ *     Issue the specified internally generated command and do command
+ *     specific cleanup. For bus scan / DV only.
+ *     NOTES: If command is Inquiry and status is good,
+ *     initialize a target structure, save the data
+ *
+ *     Remark: Single threaded access only.
+ *
+ *     Return:
+ *             < 0 if an illegal command or no resources
+ *
+ *                0 if good
+ *
+ *              > 0 if command complete but some type of completion error.
+ */
+static int
+mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSIIORequest_t *pScsiReq;
+       SCSIIORequest_t  ReqCopy;
+       int              my_idx, ii, dir;
+       int              rc, cmdTimeout;
+       int             in_isr;
+       char             cmdLen;
+       char             CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       char             cmd = io->cmd;
+
+       in_isr = in_interrupt();
+
+       if (in_isr) {
+               dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+                                       hd->ioc->name));
+               return -EPERM;
+       }
+
+
+       /* Set command specific information
+        */
+       switch (cmd) {
+       case CMD_Inquiry:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               CDB[4] = io->size;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_TestUnitReady:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_StartStopUnit:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               CDB[4] = 1;     /*Spin up the disk */
+               cmdTimeout = 15;
+               break;
+
+       case CMD_RequestSense:
+               cmdLen = 6;
+               CDB[0] = cmd;
+               CDB[4] = io->size;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_ReadBuffer:
+               cmdLen = 10;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               if (io->flags & MPT_ICFLAG_ECHO) {
+                       CDB[1] = 0x0A;
+               } else {
+                       CDB[1] = 0x02;
+               }
+
+               if (io->flags & MPT_ICFLAG_BUF_CAP) {
+                       CDB[1] |= 0x01;
+               }
+               CDB[6] = (io->size >> 16) & 0xFF;
+               CDB[7] = (io->size >>  8) & 0xFF;
+               CDB[8] = io->size & 0xFF;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_WriteBuffer:
+               cmdLen = 10;
+               dir = MPI_SCSIIO_CONTROL_WRITE;
+               CDB[0] = cmd;
+               if (io->flags & MPT_ICFLAG_ECHO) {
+                       CDB[1] = 0x0A;
+               } else {
+                       CDB[1] = 0x02;
+               }
+               CDB[6] = (io->size >> 16) & 0xFF;
+               CDB[7] = (io->size >>  8) & 0xFF;
+               CDB[8] = io->size & 0xFF;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_Reserve6:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_Release6:
+               cmdLen = 6;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+               cmdTimeout = 10;
+               break;
+
+       case CMD_SynchronizeCache:
+               cmdLen = 10;
+               dir = MPI_SCSIIO_CONTROL_READ;
+               CDB[0] = cmd;
+//             CDB[1] = 0x02;  /* set immediate bit */
+               cmdTimeout = 10;
+               break;
+
+       default:
+               /* Error Case */
+               return -EFAULT;
+       }
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(ScsiScanDvCtx, hd->ioc->id)) == NULL) {
+               ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
+                                       hd->ioc->name));
+               return -EBUSY;
+       }
+
+       pScsiReq = (SCSIIORequest_t *) mf;
+
+       /* Get the request index */
+       my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       ADD_INDEX_LOG(my_idx); /* for debug */
+
+       if (io->flags & MPT_ICFLAG_PHYS_DISK) {
+               pScsiReq->TargetID = io->physDiskNum;
+               pScsiReq->Bus = 0;
+               pScsiReq->ChainOffset = 0;
+               pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
+       } else {
+               pScsiReq->TargetID = io->id;
+               pScsiReq->Bus = io->bus;
+               pScsiReq->ChainOffset = 0;
+               pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       }
+
+       pScsiReq->CDBLength = cmdLen;
+       pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
+
+       pScsiReq->Reserved = 0;
+
+       pScsiReq->MsgFlags = mpt_msg_flags();
+       /* MsgContext set in mpt_get_msg_fram call  */
+
+       for (ii=0; ii < 8; ii++)
+               pScsiReq->LUN[ii] = 0;
+       pScsiReq->LUN[1] = io->lun;
+
+       if (io->flags & MPT_ICFLAG_TAGGED_CMD)
+               pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
+       else
+               pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+
+       if (cmd == CMD_RequestSense) {
+               pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+               ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
+                       hd->ioc->name, cmd));
+       }
+
+       for (ii=0; ii < 16; ii++)
+               pScsiReq->CDB[ii] = CDB[ii];
+
+       pScsiReq->DataLength = cpu_to_le32(io->size);
+       pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+                                          + (my_idx * MPT_SENSE_BUFFER_ALLOC));
+
+       ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+                       hd->ioc->name, cmd, io->bus, io->id, io->lun));
+
+       if (dir == MPI_SCSIIO_CONTROL_READ) {
+               mpt_add_sge((char *) &pScsiReq->SGL,
+                       MPT_SGE_FLAGS_SSIMPLE_READ | io->size,
+                       io->data_dma);
+       } else {
+               mpt_add_sge((char *) &pScsiReq->SGL,
+                       MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size,
+                       io->data_dma);
+       }
+
+       /* The ISR will free the request frame, but we need
+        * the information to initialize the target. Duplicate.
+        */
+       memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t));
+
+       /* Issue this command after:
+        *      finish init
+        *      add timer
+        * Wait until the reply has been received
+        *  ScsiScanDvCtx callback function will
+        *      set hd->pLocal;
+        *      set scandv_wait_done and call wake_up
+        */
+       hd->pLocal = NULL;
+       hd->timer.expires = jiffies + HZ*cmdTimeout;
+       scandv_wait_done = 0;
+
+       /* Save cmd pointer, for resource free if timeout or
+        * FW reload occurs
+        */
+       hd->cmdPtr = mf;
+
+       add_timer(&hd->timer);
+       mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf);
+/* SAE: No wait queues */
+#ifdef XENO_KILLED
+       wait_event(scandv_waitq, scandv_wait_done);
+#else
+       /* SAE: Decrease the wait time: 100 -> 1 */
+       while(!scandv_wait_done) {
+               mdelay(1);
+       }
+#endif
+
+       if (hd->pLocal) {
+               rc = hd->pLocal->completion;
+               hd->pLocal->skip = 0;
+
+               /* Always set fatal error codes in some cases.
+                */
+               if (rc == MPT_SCANDV_SELECTION_TIMEOUT)
+                       rc = -ENXIO;
+               else if (rc == MPT_SCANDV_SOME_ERROR)
+                       rc =  -rc;
+       } else {
+               rc = -EFAULT;
+               /* This should never happen. */
+               ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
+                               hd->ioc->name));
+       }
+
+       return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
+ *     @hd: Pointer to MPT_SCSI_HOST structure
+ *     @portnum: IOC port number
+ *
+ *     Uses the ISR, but with special processing.
+ *     MUST be single-threaded.
+ *
+ *     Return: 0 on completion
+ */
+static int
+mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
+{
+       MPT_ADAPTER             *ioc= hd->ioc;
+       VirtDevice              *pTarget = NULL;
+       SCSIDevicePage1_t       *pcfg1Data = NULL;
+       INTERNAL_CMD             iocmd;
+       CONFIGPARMS              cfg;
+       dma_addr_t               cfg1_dma_addr = -1;
+       ConfigPageHeader_t       header1;
+       int                      bus = 0;
+       int                      id = 0;
+       int                      lun = 0;
+       int                      hostId = ioc->pfacts[portnum].PortSCSIID;
+       int                      max_id;
+       int                      requested, configuration, data;
+       int                      doConfig = 0;
+       u8                       flags, factor;
+
+       max_id = ioc->sh->max_id - 1;
+
+       /* Following parameters will not change
+        * in this routine.
+        */
+       iocmd.cmd = CMD_SynchronizeCache;
+       iocmd.flags = 0;
+       iocmd.physDiskNum = -1;
+       iocmd.data = NULL;
+       iocmd.data_dma = -1;
+       iocmd.size = 0;
+       iocmd.rsvd = iocmd.rsvd2 = 0;
+
+       /* No SCSI hosts
+        */
+       if (hd->Targets == NULL)
+               return 0;
+
+       /* Skip the host
+        */
+       if (id == hostId)
+               id++;
+
+       /* Write SDP1 for all SCSI devices
+        * Alloc memory and set up config buffer
+        */
+       if (hd->is_spi) {
+               if (ioc->spi_data.sdp1length > 0) {
+                       pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
+                                        ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
+       
+                       if (pcfg1Data != NULL) {
+                               doConfig = 1;
+                               header1.PageVersion = ioc->spi_data.sdp1version;
+                               header1.PageLength = ioc->spi_data.sdp1length;
+                               header1.PageNumber = 1;
+                               header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+                               cfg.hdr = &header1;
+                               cfg.physAddr = cfg1_dma_addr;
+                               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                               cfg.dir = 1;
+                               cfg.timeout = 0;
+                       }
+               }
+       }
+
+       /* loop through all devices on this port
+        */
+       while (bus < MPT_MAX_BUS) {
+               iocmd.bus = bus;
+               iocmd.id = id;
+               pTarget = hd->Targets[(int)id];
+
+               if (doConfig) {
+
+                       /* Set the negotiation flags */
+                       if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) {
+                               flags = pTarget->negoFlags;
+                       } else {
+                               flags = hd->ioc->spi_data.noQas;
+                               if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                                       data = hd->ioc->spi_data.nvram[id];
+       
+                                       if (data & MPT_NVRAM_WIDE_DISABLE)
+                                               flags |= MPT_TARGET_NO_NEGO_WIDE;
+
+                                       factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+                                       if ((factor == 0) || (factor == MPT_ASYNC))
+                                               flags |= MPT_TARGET_NO_NEGO_SYNC;
+                               }
+                       }
+       
+                       /* Force to async, narrow */
+                       mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
+                                       &configuration, flags);
+                       pcfg1Data->RequestedParameters = le32_to_cpu(requested);
+                       pcfg1Data->Reserved = 0;
+                       pcfg1Data->Configuration = le32_to_cpu(configuration);
+                       cfg.pageAddr = (bus<<8) | id;
+                       mpt_config(hd->ioc, &cfg);
+               }
+
+               /* If target Ptr NULL or if this target is NOT a disk, skip.
+                */
+       //      if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
+               if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
+                       for (lun=0; lun <= MPT_LAST_LUN; lun++) {
+                               /* If LUN present, issue the command
+                                */
+                               if (pTarget->luns & (1<<lun)) {
+                                       iocmd.lun = lun;
+                                       (void) mptscsih_do_cmd(hd, &iocmd);
+                               }
+                       }
+               }
+
+               /* get next relevant device */
+               id++;
+
+               if (id == hostId)
+                       id++;
+
+               if (id > max_id) {
+                       id = 0;
+                       bus++;
+               }
+       }
+
+       if (pcfg1Data) {
+               pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr);
+       }
+
+       return 0;
+}
+
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_domainValidation - Top level handler for domain validation.
+ *     @hd: Pointer to MPT_SCSI_HOST structure.
+ *
+ *     Uses the ISR, but with special processing.
+ *     Called from schedule, should not be in interrupt mode.
+ *     While thread alive, do dv for all devices needing dv
+ *
+ *     Return: None.
+ */
+static void
+mptscsih_domainValidation(void *arg)
+{
+       MPT_SCSI_HOST           *hd = NULL;
+       MPT_ADAPTER             *ioc = NULL;
+       unsigned long            flags;
+       int                      id, maxid, dvStatus, did;
+       int                      ii, isPhysDisk;
+
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_active = 1;
+       if (dvtaskQ_release) {
+               dvtaskQ_active = 0;
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+       /* For this ioc, loop through all devices and do dv to each device.
+        * When complete with this ioc, search through the ioc list, and
+        * for each scsi ioc found, do dv for all devices. Exit when no
+        * device needs dv.
+        */
+       did = 1;
+       while (did) {
+               did = 0;
+               for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
+                       spin_lock_irqsave(&dvtaskQ_lock, flags);
+                       if (dvtaskQ_release) {
+                               dvtaskQ_active = 0;
+                               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                               return;
+                       }
+                       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+/* SAE: */
+#ifdef XENO_KILLED
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ/4);
+#else
+                       /* SAE: Decrease the wait time: 250 -> 100 */
+                       mdelay(100);
+#endif
+
+                       /* DV only to SCSI adapters */
+                       if ((int)ioc->chip_type <= (int)FC929)
+                               continue;
+                       
+                       /* Make sure everything looks ok */
+                       if (ioc->sh == NULL)
+                               continue;
+
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                       if (hd == NULL)
+                               continue;
+
+                       if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
+                               mpt_read_ioc_pg_3(ioc);
+                               if (ioc->spi_data.pIocPg3) {
+                                       Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
+                                       int             numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+                                       while (numPDisk) {
+                                               if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
+                                                       ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+
+                                               pPDisk++;
+                                               numPDisk--;
+                                       }
+                               }
+                               ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
+                       }
+
+                       maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
+
+                       for (id = 0; id < maxid; id++) {
+                               spin_lock_irqsave(&dvtaskQ_lock, flags);
+                               if (dvtaskQ_release) {
+                                       dvtaskQ_active = 0;
+                                       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                                       return;
+                               }
+                               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                               dvStatus = hd->ioc->spi_data.dvStatus[id];
+
+                               if (dvStatus & MPT_SCSICFG_NEED_DV) {
+                                       did++;
+                                       hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+                                       hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
+
+/* SAE: */
+#ifdef XENO_KILLED
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ/4);
+#else
+                                       /* SAE: Decrease the wait time: 250 -> 100 */
+                                       mdelay(100);
+#endif
+
+                                       /* If hidden phys disk, block IO's to all
+                                        *      raid volumes
+                                        * else, process normally
+                                        */
+                                       isPhysDisk = mptscsih_is_phys_disk(ioc, id);
+                                       if (isPhysDisk) {
+                                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                                       if (hd->ioc->spi_data.isRaid & (1 << ii)) {
+                                                               hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
+                                                       }
+                                               }
+                                       }
+
+                                       if (mptscsih_doDv(hd, 0, id) == 1) {
+                                               /* Untagged device was busy, try again
+                                                */
+                                               hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
+                                               hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+                                       } else {
+                                               /* DV is complete. Clear flags.
+                                                */
+                                               hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+                                       }
+
+                                       if (isPhysDisk) {
+                                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                                       if (hd->ioc->spi_data.isRaid & (1 << ii)) {
+                                                               hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
+                                                       }
+                                               }
+                                       }
+
+                                       /* Post OS IOs that were pended while
+                                        * DV running.
+                                        */
+                                       post_pendingQ_commands(hd);
+
+                                       if (hd->ioc->spi_data.noQas)
+                                               mptscsih_qas_check(hd, id);
+                               }
+                       }
+               }
+       }
+
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_active = 0;
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+       return;
+}
+
+/* Search IOC page 3 to determine if this is hidden physical disk
+ */
+static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
+{
+       if (ioc->spi_data.pIocPg3) {
+               Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+               int             numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+               while (numPDisk) {
+                       if (pPDisk->PhysDiskID == id) {
+                               return 1;
+                       }
+                       pPDisk++;
+                       numPDisk--;
+               }
+       }
+       return 0;
+}
+
+/* Write SDP1 if no QAS has been enabled
+ */
+static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
+{
+       VirtDevice *pTarget = NULL;
+       int ii;
+
+       if (hd->Targets == NULL)
+               return;
+
+       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+               if (ii == id)
+                       continue;
+
+               if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
+                       continue;
+
+               pTarget = hd->Targets[ii];
+
+               if ((pTarget != NULL) && (!pTarget->raidVolume)) {
+                       if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
+                               pTarget->negoFlags |= hd->ioc->spi_data.noQas;
+                               mptscsih_writeSDP1(hd, 0, ii, 0);
+                       }
+               } else {
+                       if (mptscsih_is_phys_disk(hd->ioc, ii) == 1)
+                               mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
+               }
+       }
+       return;
+}
+
+
+
+#define MPT_GET_NVRAM_VALS     0x01
+#define MPT_UPDATE_MAX         0x02
+#define MPT_SET_MAX            0x04
+#define MPT_SET_MIN            0x08
+#define MPT_FALLBACK           0x10
+#define MPT_SAVE               0x20
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_doDv - Perform domain validation to a target.
+ *     @hd: Pointer to MPT_SCSI_HOST structure.
+ *     @portnum: IOC port number.
+ *     @target: Physical ID of this target
+ *
+ *     Uses the ISR, but with special processing.
+ *     MUST be single-threaded.
+ *     Test will exit if target is at async & narrow.
+ *
+ *     Return: None.
+ */
+static int
+mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
+{
+       MPT_ADAPTER             *ioc = hd->ioc;
+       VirtDevice              *pTarget = NULL;
+       SCSIDevicePage1_t       *pcfg1Data = NULL;
+       SCSIDevicePage0_t       *pcfg0Data = NULL;
+       u8                      *pbuf1 = NULL;
+       u8                      *pbuf2 = NULL;
+       u8                      *pDvBuf = NULL;
+       dma_addr_t               dvbuf_dma = -1;
+       dma_addr_t               buf1_dma = -1;
+       dma_addr_t               buf2_dma = -1;
+       dma_addr_t               cfg1_dma_addr = -1;
+       dma_addr_t               cfg0_dma_addr = -1;
+       ConfigPageHeader_t       header1;
+       ConfigPageHeader_t       header0;
+       DVPARAMETERS             dv;
+       INTERNAL_CMD             iocmd;
+       CONFIGPARMS              cfg;
+       int                      dv_alloc = 0;
+       int                      rc, sz = 0;
+       int                      bufsize = 0;
+       int                      dataBufSize = 0;
+       int                      echoBufSize = 0;
+       int                      notDone;
+       int                      patt;
+       int                      repeat;
+       int                      retcode = 0;
+       int                      nfactor =  MPT_ULTRA320;
+       char                     firstPass = 1;
+       char                     doFallback = 0;
+       char                     readPage0;
+       char                     bus, lun;
+       char                     inq0 = 0;
+
+       if (ioc->spi_data.sdp1length == 0)
+               return 0;
+
+       if (ioc->spi_data.sdp0length == 0)
+               return 0;
+
+       /* If multiple buses are used, require that the initiator
+        * id be the same on all buses.
+        */
+       if (id == ioc->pfacts[0].PortSCSIID)
+               return 0;
+
+       lun = 0;
+       bus = (u8) bus_number;
+       ddvtprintk((MYIOC_s_NOTE_FMT
+                       "DV started: numIOs %d bus=%d, id %d dv @ %p\n",
+                       ioc->name, atomic_read(&queue_depth), bus, id, &dv));
+
+       /* Prep DV structure
+        */
+       memset (&dv, 0, sizeof(DVPARAMETERS));
+       dv.id = id;
+
+       /* Populate tmax with the current maximum
+        * transfer parameters for this target.
+        * Exit if narrow and async.
+        */
+       dv.cmd = MPT_GET_NVRAM_VALS;
+       mptscsih_dv_parms(hd, &dv, NULL);
+       if ((!dv.max.width) && (!dv.max.offset))
+               return 0;
+
+       /* Prep SCSI IO structure
+        */
+       iocmd.id = id;
+       iocmd.bus = bus;
+       iocmd.lun = lun;
+       iocmd.flags = 0;
+       iocmd.physDiskNum = -1;
+       iocmd.rsvd = iocmd.rsvd2 = 0;
+
+       pTarget = hd->Targets[id];
+       if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+               /* Another GEM workaround. Check peripheral device type,
+                * if PROCESSOR, quit DV.
+                */
+               if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
+                       pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+                       return 0;
+               }
+       }
+
+       /* Use tagged commands if possible.
+        */
+       if (pTarget) {
+               if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+                       iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+               else {
+                       if (hd->ioc->facts.FWVersion.Word < 0x01000600)
+                               return 0;
+
+                       if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+                               (hd->ioc->facts.FWVersion.Word < 0x01010B00))
+                               return 0;
+               }
+       }
+
+       /* Prep cfg structure
+        */
+       cfg.pageAddr = (bus<<8) | id;
+       cfg.hdr = NULL;
+
+       /* Prep SDP0 header
+        */
+       header0.PageVersion = ioc->spi_data.sdp0version;
+       header0.PageLength = ioc->spi_data.sdp0length;
+       header0.PageNumber = 0;
+       header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+       /* Prep SDP1 header
+        */
+       header1.PageVersion = ioc->spi_data.sdp1version;
+       header1.PageLength = ioc->spi_data.sdp1length;
+       header1.PageNumber = 1;
+       header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+       if (header0.PageLength & 1)
+               dv_alloc = (header0.PageLength * 4) + 4;
+
+       dv_alloc +=  (2048 + (header1.PageLength * 4));
+
+       pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
+       if (pDvBuf == NULL)
+               return 0;
+
+       sz = 0;
+       pbuf1 = (u8 *)pDvBuf;
+       buf1_dma = dvbuf_dma;
+       sz +=1024;
+
+       pbuf2 = (u8 *) (pDvBuf + sz);
+       buf2_dma = dvbuf_dma + sz;
+       sz +=1024;
+
+       pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
+       cfg0_dma_addr = dvbuf_dma + sz;
+       sz += header0.PageLength * 4;
+
+       /* 8-byte alignment
+        */
+       if (header0.PageLength & 1)
+               sz += 4;
+
+       pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
+       cfg1_dma_addr = dvbuf_dma + sz;
+
+       /* Skip this ID? Set cfg.hdr to force config page write
+        */
+       {
+               ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+               if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                       /* Set the factor from nvram */
+                       nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
+                       if (nfactor < pspi_data->minSyncFactor )
+                               nfactor = pspi_data->minSyncFactor;
+       
+                       if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE)) {
+       
+                               ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
+                                       ioc->name, bus, id, lun));
+       
+                               dv.cmd = MPT_SET_MAX;
+                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+                               cfg.hdr = &header1;
+       
+                               /* Save the final negotiated settings to
+                                * SCSI device page 1.
+                                */
+                               cfg.physAddr = cfg1_dma_addr;
+                               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                               cfg.dir = 1;
+                               mpt_config(hd->ioc, &cfg);
+                               goto target_done;
+                       }
+               }
+       }
+
+       /* Finish iocmd inititialization - hidden or visible disk? */
+       if (ioc->spi_data.pIocPg3) {
+               /* Searc IOC page 3 for matching id
+                */
+               Ioc3PhysDisk_t *pPDisk =  ioc->spi_data.pIocPg3->PhysDisk;
+               int             numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
+
+               while (numPDisk) {
+                       if (pPDisk->PhysDiskID == id) {
+                               /* match */
+                               iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
+                               iocmd.physDiskNum = pPDisk->PhysDiskNum;
+
+                               /* Quiesce the IM
+                                */
+                               if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
+                                       ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+                                       goto target_done;
+                               }
+                               break;
+                       }
+                       pPDisk++;
+                       numPDisk--;
+               }
+       }
+
+       /* RAID Volume ID's may double for a physical device. If RAID but
+        * not a physical ID as well, skip DV.
+        */
+       if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
+               goto target_done;
+
+
+       /* Basic Test.
+        * Async & Narrow - Inquiry
+        * Async & Narrow - Inquiry
+        * Maximum transfer rate - Inquiry
+        * Compare buffers:
+        *      If compare, test complete.
+        *      If miscompare and first pass, repeat
+        *      If miscompare and not first pass, fall back and repeat
+        */
+       hd->pLocal = NULL;
+       readPage0 = 0;
+       sz = SCSI_STD_INQUIRY_BYTES;
+       rc = MPT_SCANDV_GOOD;
+       while (1) {
+               ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+               retcode = 0;
+               dv.cmd = MPT_SET_MIN;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+               cfg.hdr = &header1;
+               cfg.physAddr = cfg1_dma_addr;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               cfg.dir = 1;
+               if (mpt_config(hd->ioc, &cfg) != 0)
+                       goto target_done;
+
+               /* Wide - narrow - wide workaround case
+                */
+               if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
+                       /* Send an untagged command to reset disk Qs corrupted
+                        * when a parity error occurs on a Request Sense.
+                        */
+                       if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
+                               ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+                               (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
+
+                               iocmd.cmd = CMD_RequestSense;
+                               iocmd.data_dma = buf1_dma;
+                               iocmd.data = pbuf1;
+                               iocmd.size = 0x12;
+                               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                                       goto target_done;
+                               else {
+                                       if (hd->pLocal == NULL)
+                                               goto target_done;
+                                       rc = hd->pLocal->completion;
+                                       if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
+                                               dv.max.width = 0;
+                                               doFallback = 0;
+                                       } else
+                                               goto target_done;
+                               }
+                       } else
+                               goto target_done;
+               }
+
+               iocmd.cmd = CMD_Inquiry;
+               iocmd.data_dma = buf1_dma;
+               iocmd.data = pbuf1;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else {
+                       if (hd->pLocal == NULL)
+                               goto target_done;
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD) {
+                               if (hd->pLocal->scsiStatus == STS_BUSY) {
+                                       if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
+                                               retcode = 1;
+                                       else
+                                               retcode = 0;
+
+                                       goto target_done;
+                               }
+                       } else if  (rc == MPT_SCANDV_SENSE) {
+                               ;
+                       } else {
+                               /* If first command doesn't complete
+                                * with a good status or with a check condition,
+                                * exit.
+                                */
+                               goto target_done;
+                       }
+               }
+
+               /* Reset the size for disks
+                */
+               inq0 = (*pbuf1) & 0x1F;
+               if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
+                       sz = 0x40;
+                       iocmd.size = sz;
+               }
+
+               /* Another GEM workaround. Check peripheral device type,
+                * if PROCESSOR, quit DV.
+                */
+               if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08))
+                       goto target_done;
+
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               if (sz == 0x40) {
+                       if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
+                               && (pTarget->minSyncFactor > 0x09)) {
+                               if ((pbuf1[56] & 0x04) == 0)
+                                       ;
+                               else if ((pbuf1[56] & 0x01) == 1) {
+                                       pTarget->minSyncFactor = nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
+                               } else {
+                                       pTarget->minSyncFactor = nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
+                               }
+
+                               dv.max.factor = pTarget->minSyncFactor;
+
+                               if ((pbuf1[56] & 0x02) == 0) {
+                                       pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+                                       hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+                               }
+                       }
+               }
+
+               if (doFallback)
+                       dv.cmd = MPT_FALLBACK;
+               else
+                       dv.cmd = MPT_SET_MAX;
+
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+               if (mpt_config(hd->ioc, &cfg) != 0)
+                       goto target_done;
+
+               if ((!dv.now.width) && (!dv.now.offset))
+                       goto target_done;
+
+               iocmd.cmd = CMD_Inquiry;
+               iocmd.data_dma = buf2_dma;
+               iocmd.data = pbuf2;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       /* Save the return code.
+                        * If this is the first pass,
+                        * read SCSI Device Page 0
+                        * and update the target max parameters.
+                        */
+                       rc = hd->pLocal->completion;
+                       doFallback = 0;
+                       if (rc == MPT_SCANDV_GOOD) {
+                               if (!readPage0) {
+                                       u32 sdp0_info;
+                                       u32 sdp0_nego;
+
+                                       cfg.hdr = &header0;
+                                       cfg.physAddr = cfg0_dma_addr;
+                                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                                       cfg.dir = 0;
+
+                                       if (mpt_config(hd->ioc, &cfg) != 0)
+                                               goto target_done;
+
+                                       sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
+                                       sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
+
+                                       /* Quantum and Fujitsu workarounds.
+                                        * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
+                                        * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
+                                        * Resetart with a request for U160.
+                                        */
+                                       if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
+                                                       doFallback = 1;
+                                       } else {
+                                               dv.cmd = MPT_UPDATE_MAX;
+                                               mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
+                                               /* Update the SCSI device page 1 area
+                                                */
+                                               pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
+                                               readPage0 = 1;
+                                       }
+                               }
+
+                               /* Quantum workaround. Restart this test will the fallback
+                                * flag set.
+                                */
+                               if (doFallback == 0) {
+                                       if (memcmp(pbuf1, pbuf2, sz) != 0) {
+                                               if (!firstPass)
+                                                       doFallback = 1;
+                                       } else
+                                               break;  /* test complete */
+                               }
+
+
+                       } else if (rc == MPT_SCANDV_ISSUE_SENSE)
+                               doFallback = 1; /* set fallback flag */
+                       else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
+                               doFallback = 1; /* set fallback flag */
+                       else
+                               goto target_done;
+
+                       firstPass = 0;
+               }
+       }
+       ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name));
+       inq0 = (*pbuf1) & 0x1F;
+
+       /* Continue only for disks
+        */
+       if (inq0 != 0)
+               goto target_done;
+
+       /* Start the Enhanced Test.
+        * 0) issue TUR to clear out check conditions
+        * 1) read capacity of echo (regular) buffer
+        * 2) reserve device
+        * 3) do write-read-compare data pattern test
+        * 4) release
+        * 5) update nego parms to target struct
+        */
+       cfg.hdr = &header1;
+       cfg.physAddr = cfg1_dma_addr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       cfg.dir = 1;
+
+       iocmd.cmd = CMD_TestUnitReady;
+       iocmd.data_dma = -1;
+       iocmd.data = NULL;
+       iocmd.size = 0;
+       notDone = 1;
+       while (notDone) {
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               if (hd->pLocal == NULL)
+                       goto target_done;
+
+               rc = hd->pLocal->completion;
+               if (rc == MPT_SCANDV_GOOD)
+                       notDone = 0;
+               else if (rc == MPT_SCANDV_SENSE) {
+                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                       u8 asc = hd->pLocal->sense[12];
+                       u8 ascq = hd->pLocal->sense[13];
+                       ddvprintk((MYIOC_s_INFO_FMT
+                               "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                               ioc->name, skey, asc, ascq));
+
+                       if (skey == SK_UNIT_ATTENTION)
+                               notDone++; /* repeat */
+                       else if ((skey == SK_NOT_READY) &&
+                                       (asc == 0x04)&&(ascq == 0x01)) {
+                               /* wait then repeat */
+                               mdelay (2000);
+                               notDone++;
+                       } else if ((skey == SK_NOT_READY) && (asc == 0x3A)) {
+                               /* no medium, try read test anyway */
+                               notDone = 0;
+                       } else {
+                               /* All other errors are fatal.
+                                */
+                               ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+                                               ioc->name));
+                               goto target_done;
+                       }
+               } else
+                       goto target_done;
+       }
+
+       iocmd.cmd = CMD_ReadBuffer;
+       iocmd.data_dma = buf1_dma;
+       iocmd.data = pbuf1;
+       iocmd.size = 4;
+       iocmd.flags |= MPT_ICFLAG_BUF_CAP;
+
+       dataBufSize = 0;
+       echoBufSize = 0;
+       for (patt = 0; patt < 2; patt++) {
+               if (patt == 0)
+                       iocmd.flags |= MPT_ICFLAG_ECHO;
+               else
+                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+
+               notDone = 1;
+               while (notDone) {
+                       bufsize = 0;
+
+                       /* If not ready after 8 trials,
+                        * give up on this device.
+                        */
+                       if (notDone > 8)
+                               goto target_done;
+
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               ddvprintk(("ReadBuffer Comp Code %d", rc));
+                               ddvprintk(("  buff: %0x %0x %0x %0x\n",
+                                       pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
+
+                               if (rc == MPT_SCANDV_GOOD) {
+                                       notDone = 0;
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               bufsize =  ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
+                                       } else {
+                                               bufsize =  pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
+                                       }
+                               } else if (rc == MPT_SCANDV_SENSE) {
+                                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                                       u8 asc = hd->pLocal->sense[12];
+                                       u8 ascq = hd->pLocal->sense[13];
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                                               ioc->name, skey, asc, ascq));
+                                       if (skey == SK_ILLEGAL_REQUEST) {
+                                               notDone = 0;
+                                       } else if (skey == SK_UNIT_ATTENTION) {
+                                               notDone++; /* repeat */
+                                       } else if ((skey == SK_NOT_READY) &&
+                                               (asc == 0x04)&&(ascq == 0x01)) {
+                                               /* wait then repeat */
+                                               mdelay (2000);
+                                               notDone++;
+                                       } else {
+                                               /* All other errors are fatal.
+                                                */
+                                               ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+                                                       ioc->name));
+                                               goto target_done;
+                                       }
+                               } else {
+                                       /* All other errors are fatal
+                                        */
+                                       goto target_done;
+                               }
+                       }
+               }
+
+               if (iocmd.flags & MPT_ICFLAG_ECHO)
+                       echoBufSize = bufsize;
+               else
+                       dataBufSize = bufsize;
+       }
+       sz = 0;
+       iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
+
+       /* Use echo buffers if possible,
+        * Exit if both buffers are 0.
+        */
+       if (echoBufSize > 0) {
+               iocmd.flags |= MPT_ICFLAG_ECHO;
+               if (dataBufSize > 0)
+                       bufsize = MIN(echoBufSize, dataBufSize);
+               else
+                       bufsize = echoBufSize;
+       } else if (dataBufSize == 0)
+               goto target_done;
+
+       ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
+               (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
+
+       /* Data buffers for write-read-compare test max 1K.
+        */
+       sz = MIN(bufsize, 1024);
+
+       /* --- loop ----
+        * On first pass, always issue a reserve.
+        * On additional loops, only if a reset has occurred.
+        * iocmd.flags indicates if echo or regular buffer
+        */
+       for (patt = 0; patt < 4; patt++) {
+               ddvprintk(("Pattern %d\n", patt));
+               if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
+                       iocmd.cmd = CMD_TestUnitReady;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+
+                       iocmd.cmd = CMD_Release6;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               ddvprintk(("Release rc %d\n", rc));
+                               if (rc == MPT_SCANDV_GOOD)
+                                       iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+                               else
+                                       goto target_done;
+                       }
+                       iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+               }
+               iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
+
+               repeat = 5;
+               while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
+                       iocmd.cmd = CMD_Reserve6;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               if (rc == MPT_SCANDV_GOOD) {
+                                       iocmd.flags |= MPT_ICFLAG_RESERVED;
+                               } else if (rc == MPT_SCANDV_SENSE) {
+                                       /* Wait if coming ready
+                                        */
+                                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                                       u8 asc = hd->pLocal->sense[12];
+                                       u8 ascq = hd->pLocal->sense[13];
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "DV: Reserve Failed: ", ioc->name));
+                                       ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                                                       skey, asc, ascq));
+
+                                       if ((skey == SK_NOT_READY) && (asc == 0x04)&&
+                                                                       (ascq == 0x01)) {
+                                               /* wait then repeat */
+                                               mdelay (2000);
+                                               notDone++;
+                                       } else {
+                                               ddvprintk((MYIOC_s_INFO_FMT
+                                                       "DV: Reserved Failed.", ioc->name));
+                                               goto target_done;
+                                       }
+                               } else {
+                                       ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
+                                                        ioc->name));
+                                       goto target_done;
+                               }
+                       }
+               }
+
+               mptscsih_fillbuf(pbuf1, sz, patt, 1);
+               iocmd.cmd = CMD_WriteBuffer;
+               iocmd.data_dma = buf1_dma;
+               iocmd.data = pbuf1;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD)
+                               ;               /* Issue read buffer */
+                       else if (rc == MPT_SCANDV_DID_RESET) {
+                               /* If using echo buffers, reset to data buffers.
+                                * Else do Fallback and restart
+                                * this test (re-issue reserve
+                                * because of bus reset).
+                                */
+                               if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
+                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                               } else {
+                                       dv.cmd = MPT_FALLBACK;
+                                       mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                                       if (mpt_config(hd->ioc, &cfg) != 0)
+                                               goto target_done;
+
+                                       if ((!dv.now.width) && (!dv.now.offset))
+                                               goto target_done;
+                               }
+
+                               iocmd.flags |= MPT_ICFLAG_DID_RESET;
+                               patt = -1;
+                               continue;
+                       } else if (rc == MPT_SCANDV_SENSE) {
+                               /* Restart data test if UA, else quit.
+                                */
+                               u8 skey = hd->pLocal->sense[2] & 0x0F;
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+                                       hd->pLocal->sense[12], hd->pLocal->sense[13]));
+                               if (skey == SK_UNIT_ATTENTION) {
+                                       patt = -1;
+                                       continue;
+                               } else if (skey == SK_ILLEGAL_REQUEST) {
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               if (dataBufSize >= bufsize) {
+                                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                                                       patt = -1;
+                                                       continue;
+                                               }
+                                       }
+                                       goto target_done;
+                               }
+                               else
+                                       goto target_done;
+                       } else {
+                               /* fatal error */
+                               goto target_done;
+                       }
+               }
+
+               iocmd.cmd = CMD_ReadBuffer;
+               iocmd.data_dma = buf2_dma;
+               iocmd.data = pbuf2;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD) {
+                                /* If buffers compare,
+                                 * go to next pattern,
+                                 * else, do a fallback and restart
+                                 * data transfer test.
+                                 */
+                               if (memcmp (pbuf1, pbuf2, sz) == 0) {
+                                       ; /* goto next pattern */
+                               } else {
+                                       /* Miscompare with Echo buffer, go to data buffer,
+                                        * if that buffer exists.
+                                        * Miscompare with Data buffer, check first 4 bytes,
+                                        * some devices return capacity. Exit in this case.
+                                        */
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               if (dataBufSize >= bufsize)
+                                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                                               else
+                                                       goto target_done;
+                                       } else {
+                                               if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
+                                                       /* Argh. Device returning wrong data.
+                                                        * Quit DV for this device.
+                                                        */
+                                                       goto target_done;
+                                               }
+
+                                               /* Had an actual miscompare. Slow down.*/
+                                               dv.cmd = MPT_FALLBACK;
+                                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                                               if (mpt_config(hd->ioc, &cfg) != 0)
+                                                       goto target_done;
+
+                                               if ((!dv.now.width) && (!dv.now.offset))
+                                                       goto target_done;
+                                       }
+
+                                       patt = -1;
+                                       continue;
+                               }
+                       } else if (rc == MPT_SCANDV_DID_RESET) {
+                               /* Do Fallback and restart
+                                * this test (re-issue reserve
+                                * because of bus reset).
+                                */
+                               dv.cmd = MPT_FALLBACK;
+                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                               if (mpt_config(hd->ioc, &cfg) != 0)
+                                        goto target_done;
+
+                               if ((!dv.now.width) && (!dv.now.offset))
+                                       goto target_done;
+
+                               iocmd.flags |= MPT_ICFLAG_DID_RESET;
+                               patt = -1;
+                               continue;
+                       } else if (rc == MPT_SCANDV_SENSE) {
+                               /* Restart data test if UA, else quit.
+                                */
+                               u8 skey = hd->pLocal->sense[2] & 0x0F;
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+                                       hd->pLocal->sense[12], hd->pLocal->sense[13]));
+                               if (skey == SK_UNIT_ATTENTION) {
+                                       patt = -1;
+                                       continue;
+                               }
+                               else
+                                       goto target_done;
+                       } else {
+                               /* fatal error */
+                               goto target_done;
+                       }
+               }
+
+       } /* --- end of patt loop ---- */
+
+target_done:
+       if (iocmd.flags & MPT_ICFLAG_RESERVED) {
+               iocmd.cmd = CMD_Release6;
+               iocmd.data_dma = -1;
+               iocmd.data = NULL;
+               iocmd.size = 0;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
+                                       ioc->name, id);
+               else if (hd->pLocal) {
+                       if (hd->pLocal->completion == MPT_SCANDV_GOOD)
+                               iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+               } else {
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
+                                               ioc->name, id);
+               }
+       }
+
+
+       /* Set if cfg1_dma_addr contents is valid
+        */
+       if ((cfg.hdr != NULL) && (retcode == 0)){
+               /* If disk, not U320, disable QAS
+                */
+               if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
+                       hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+
+               dv.cmd = MPT_SAVE;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+               /* Double writes to SDP1 can cause problems,
+                * skip save of the final negotiated settings to
+                * SCSI device page 1.
+                *
+               cfg.hdr = &header1;
+               cfg.physAddr = cfg1_dma_addr;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               cfg.dir = 1;
+               mpt_config(hd->ioc, &cfg);
+                */
+       }
+
+       /* If this is a RAID Passthrough, enable internal IOs
+        */
+       if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
+               if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
+                       ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
+       }
+
+       /* Done with the DV scan of the current target
+        */
+       if (pDvBuf)
+               pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
+
+       ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
+                       ioc->name, atomic_read(&queue_depth)));
+
+       return retcode;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_dv_parms - perform a variety of operations on the
+ *     parameters used for negotiation.
+ *     @hd: Pointer to a SCSI host.
+ *     @dv: Pointer to a structure that contains the maximum and current
+ *             negotiated parameters.
+ */
+static void
+mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
+{
+       VirtDevice              *pTarget = NULL;
+       SCSIDevicePage0_t       *pPage0 = NULL;
+       SCSIDevicePage1_t       *pPage1 = NULL;
+       int                     val = 0, data, configuration;
+       u8                      width = 0;
+       u8                      offset = 0;
+       u8                      factor = 0;
+       u8                      negoFlags = 0;
+       u8                      cmd = dv->cmd;
+       u8                      id = dv->id;
+
+       switch (cmd) {
+       case MPT_GET_NVRAM_VALS:
+               ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
+                                                        hd->ioc->name));
+               /* Get the NVRAM values and save in tmax
+                * If not an LVD bus, the adapter minSyncFactor has been
+                * already throttled back.
+                */
+               if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
+                       width = pTarget->maxWidth;
+                       offset = pTarget->maxOffset;
+                       factor = pTarget->minSyncFactor;
+                       negoFlags = pTarget->negoFlags;
+               } else {
+                       if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                               data = hd->ioc->spi_data.nvram[id];
+                               width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+                               if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
+                                       factor = MPT_ASYNC;
+                               else {
+                                       factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+                                       if ((factor == 0) || (factor == MPT_ASYNC)){
+                                               factor = MPT_ASYNC;
+                                               offset = 0;
+                                       }
+                               }
+                       } else {
+                               width = MPT_NARROW;
+                               offset = 0;
+                               factor = MPT_ASYNC;
+                       }
+
+                       /* Set the negotiation flags */
+                       negoFlags = hd->ioc->spi_data.noQas;
+                       if (!width)
+                               negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+                       if (!offset)
+                               negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+               }
+
+               /* limit by adapter capabilities */
+               width = MIN(width, hd->ioc->spi_data.maxBusWidth);
+               offset = MIN(offset, hd->ioc->spi_data.maxSyncOffset);
+               factor = MAX(factor, hd->ioc->spi_data.minSyncFactor);
+
+               /* Check Consistency */
+               if (offset && (factor < MPT_ULTRA2) && !width)
+                       factor = MPT_ULTRA2;
+
+               dv->max.width = width;
+               dv->max.offset = offset;
+               dv->max.factor = factor;
+               dv->max.flags = negoFlags;
+               ddvprintk((" width %d, factor %x, offset %x flags %x\n",
+                               width, factor, offset, negoFlags));
+               break;
+
+       case MPT_UPDATE_MAX:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Updating with SDP0 Data: ", hd->ioc->name));
+               /* Update tmax values with those from Device Page 0.*/
+               pPage0 = (SCSIDevicePage0_t *) pPage;
+               if (pPage0) {
+                       val = cpu_to_le32(pPage0->NegotiatedParameters);
+                       dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
+                       dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
+                       dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
+               }
+
+               dv->now.width = dv->max.width;
+               dv->now.offset = dv->max.offset;
+               dv->now.factor = dv->max.factor;
+               ddvprintk(("width %d, factor %x, offset %x, flags %x\n",
+                               dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
+               break;
+
+       case MPT_SET_MAX:
+               ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
+                                                               hd->ioc->name));
+               /* Set current to the max values. Update the config page.*/
+               dv->now.width = dv->max.width;
+               dv->now.offset = dv->max.offset;
+               dv->now.factor = dv->max.factor;
+               dv->now.flags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
+                               dv->now.offset, &val, &configuration, dv->now.flags);
+                       pPage1->RequestedParameters = le32_to_cpu(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = le32_to_cpu(configuration);
+
+               }
+
+               ddvprintk(("width %d, factor %x, offset %x request %x, config %x\n",
+                               dv->now.width, dv->now.factor, dv->now.offset, val, configuration));
+               break;
+
+       case MPT_SET_MIN:
+               ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
+                                                               hd->ioc->name));
+               /* Set page to asynchronous and narrow
+                * Do not update now, breaks fallback routine. */
+               width = MPT_NARROW;
+               offset = 0;
+               factor = MPT_ASYNC;
+               negoFlags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (width, factor,
+                               offset, &val, &configuration, negoFlags);
+                       pPage1->RequestedParameters = le32_to_cpu(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = le32_to_cpu(configuration);
+               }
+               ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
+                               width, factor, offset, val, configuration));
+               break;
+
+       case MPT_FALLBACK:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Fallback: Start: offset %d, factor %x, width %d \n",
+                               hd->ioc->name, dv->now.offset,
+                               dv->now.factor, dv->now.width));
+               width = dv->now.width;
+               offset = dv->now.offset;
+               factor = dv->now.factor;
+               if ((offset) && (dv->max.width)) {
+                       if (factor < MPT_ULTRA160)
+                               factor = MPT_ULTRA160;
+                       else if (factor < MPT_ULTRA2) {
+                               factor = MPT_ULTRA2;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_ULTRA2) && width) {
+                               factor = MPT_ULTRA2;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_ULTRA) {
+                               factor = MPT_ULTRA;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_ULTRA) && width) {
+                               factor = MPT_ULTRA;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_FAST) {
+                               factor = MPT_FAST;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_FAST) && width) {
+                               factor = MPT_FAST;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_SCSI) {
+                               factor = MPT_SCSI;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_SCSI) && width) {
+                               factor = MPT_SCSI;
+                               width = MPT_NARROW;
+                       } else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+
+               } else if (offset) {
+                       width = MPT_NARROW;
+                       if (factor < MPT_ULTRA)
+                               factor = MPT_ULTRA;
+                       else if (factor < MPT_FAST)
+                               factor = MPT_FAST;
+                       else if (factor < MPT_SCSI)
+                               factor = MPT_SCSI;
+                       else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+
+               } else {
+                       width = MPT_NARROW;
+                       factor = MPT_ASYNC;
+               }
+               dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
+
+               dv->now.width = width;
+               dv->now.offset = offset;
+               dv->now.factor = factor;
+               dv->now.flags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (width, factor, offset, &val,
+                                               &configuration, dv->now.flags);
+
+                       pPage1->RequestedParameters = le32_to_cpu(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = le32_to_cpu(configuration);
+               }
+
+               ddvprintk(("Finish: offset %d, factor %x, width %d, request %x config %x\n",
+                            dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
+               break;
+
+       case MPT_SAVE:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Saving to Target structure: ", hd->ioc->name));
+               ddvprintk(("offset %d, factor %x, width %d \n",
+                            dv->now.offset, dv->now.factor, dv->now.width));
+
+               /* Save these values to target structures
+                * or overwrite nvram (phys disks only).
+                */
+
+               if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) {
+                       pTarget->maxWidth = dv->now.width;
+                       pTarget->maxOffset = dv->now.offset;
+                       pTarget->minSyncFactor = dv->now.factor;
+                       pTarget->negoFlags = dv->now.flags;
+               } else {
+                       /* Preserv all flags, use
+                        * read-modify-write algorithm
+                        */
+                       if (hd->ioc->spi_data.nvram) {
+                               data = hd->ioc->spi_data.nvram[id];
+
+                               if (dv->now.width)
+                                       data &= ~MPT_NVRAM_WIDE_DISABLE;
+                               else
+                                       data |= MPT_NVRAM_WIDE_DISABLE;
+
+                               if (!dv->now.offset)
+                                       factor = MPT_ASYNC;
+
+                               data &= ~MPT_NVRAM_SYNC_MASK;
+                               data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
+
+                               hd->ioc->spi_data.nvram[id] = data;
+                       }
+               }
+               break;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_fillbuf - fill a buffer with a special data pattern
+ *             cleanup. For bus scan only.
+ *
+ *     @buffer: Pointer to data buffer to be filled.
+ *     @size: Number of bytes to fill
+ *     @index: Pattern index
+ *     @width: bus width, 0 (8 bits) or 1 (16 bits)
+ */
+static void
+mptscsih_fillbuf(char *buffer, int size, int index, int width)
+{
+       char *ptr = buffer;
+       int ii;
+       char byte;
+       short val;
+
+       switch (index) {
+       case 0:
+
+               if (width) {
+                       /* Pattern:  0000 FFFF 0000 FFFF
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x02)
+                                       *ptr = 0xFF;
+                               else
+                                       *ptr = 0x00;
+                       }
+               } else {
+                       /* Pattern:  00 FF 00 FF
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x01)
+                                       *ptr = 0xFF;
+                               else
+                                       *ptr = 0x00;
+                       }
+               }
+               break;
+
+       case 1:
+               if (width) {
+                       /* Pattern:  5555 AAAA 5555 AAAA 5555
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x02)
+                                       *ptr = 0xAA;
+                               else
+                                       *ptr = 0x55;
+                       }
+               } else {
+                       /* Pattern:  55 AA 55 AA 55
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x01)
+                                       *ptr = 0xAA;
+                               else
+                                       *ptr = 0x55;
+                       }
+               }
+               break;
+
+       case 2:
+               /* Pattern:  00 01 02 03 04 05
+                * ... FE FF 00 01..
+                */
+               for (ii=0; ii < size; ii++, ptr++)
+                       *ptr = (char) ii;
+               break;
+
+       case 3:
+               if (width) {
+                       /* Wide Pattern:  FFFE 0001 FFFD 0002
+                        * ...  4000 DFFF 8000 EFFF
+                        */
+                       byte = 0;
+                       for (ii=0; ii < size/2; ii++) {
+                               /* Create the base pattern
+                                */
+                               val = (1 << byte);
+                               /* every 64 (0x40) bytes flip the pattern
+                                * since we fill 2 bytes / iteration,
+                                * test for ii = 0x20
+                                */
+                               if (ii & 0x20)
+                                       val = ~(val);
+
+                               if (ii & 0x01) {
+                                       *ptr = (char)( (val & 0xFF00) >> 8);
+                                       ptr++;
+                                       *ptr = (char)(val & 0xFF);
+                                       byte++;
+                                       byte &= 0x0F;
+                               } else {
+                                       val = ~val;
+                                       *ptr = (char)( (val & 0xFF00) >> 8);
+                                       ptr++;
+                                       *ptr = (char)(val & 0xFF);
+                               }
+
+                               ptr++;
+                       }
+               } else {
+                       /* Narrow Pattern:  FE 01 FD 02 FB 04
+                        * .. 7F 80 01 FE 02 FD ...  80 7F
+                        */
+                       byte = 0;
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               /* Base pattern - first 32 bytes
+                                */
+                               if (ii & 0x01) {
+                                       *ptr = (1 << byte);
+                                       byte++;
+                                       byte &= 0x07;
+                               } else {
+                                       *ptr = (char) (~(1 << byte));
+                               }
+
+                               /* Flip the pattern every 32 bytes
+                                */
+                               if (ii & 0x20)
+                                       *ptr = ~(*ptr);
+                       }
+               }
+               break;
+       }
+}
+#endif /* ~MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Commandline Parsing routines and defines.
+ *
+ * insmod format:
+ *     insmod mptscsih mptscsih="width:1 dv:n factor:0x09"
+ *  boot format:
+ *     mptscsih=width:1,dv:n,factor:0x8
+ *
+ */
+#ifdef MODULE
+#define        ARG_SEP ' '
+#else
+#define        ARG_SEP ','
+#endif
+
+static char setup_token[] __initdata =
+       "dv:"
+       "width:"
+       "factor:"
+       ;       /* DONNOT REMOVE THIS ';' */
+
+#define OPT_DV                 1
+#define OPT_MAX_WIDTH          2
+#define OPT_MIN_SYNC_FACTOR    3
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+__init get_setup_token(char *p)
+{
+       char *cur = setup_token;
+       char *pc;
+       int i = 0;
+
+       while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+               ++pc;
+               ++i;
+               if (!strncmp(p, cur, pc - cur))
+                       return i;
+               cur = pc;
+       }
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+__init mptscsih_setup(char *str)
+{
+       char *cur = str;
+       char *pc, *pv;
+       unsigned long val;
+       int  c;
+
+       while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+               char *pe;
+
+               val = 0;
+               pv = pc;
+               c = *++pv;
+
+               if      (c == 'n')
+                       val = 0;
+               else if (c == 'y')
+                       val = 1;
+               else
+                       val = (int) simple_strtoul(pv, &pe, 0);
+
+               printk("Found Token: %s, value %x\n", cur, (int)val);
+               switch (get_setup_token(cur)) {
+               case OPT_DV:
+                       driver_setup.dv = val;
+                       break;
+
+               case OPT_MAX_WIDTH:
+                       driver_setup.max_width = val;
+                       break;
+
+               case OPT_MIN_SYNC_FACTOR:
+                       driver_setup.min_sync_fac = val;
+                       break;
+
+               default:
+                       printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+                       break;
+               }
+
+               if ((cur = strchr(cur, ARG_SEP)) != NULL)
+                       ++cur;
+       }
+       return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
diff --git a/xen/drivers/message/fusion/mptscsih.h b/xen/drivers/message/fusion/mptscsih.h
new file mode 100644 (file)
index 0000000..eaa75be
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ *  linux/drivers/message/fusion/mptscsih.h
+ *      High performance SCSI / Fibre Channel SCSI Host device driver.
+ *      For use with PCI chip/adapter(s):
+ *          LSIFC9xx/LSI409xx Fibre Channel
+ *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Credits:
+ *      This driver would not exist if not for Alan Cox's development
+ *      of the linux i2o driver.
+ *
+ *      A huge debt of gratitude is owed to David S. Miller (DaveM)
+ *      for fixing much of the stupid and broken stuff in the early
+ *      driver while porting to sparc64 platform.  THANK YOU!
+ *
+ *      (see also mptbase.c)
+ *
+ *  Copyright (c) 1999-2002 LSI Logic Corporation
+ *  Originally By: Steven J. Ralston
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:lstephens@lsil.com)
+ *
+ *  $Id: mptscsih.h,v 1.1.2.2 2003/05/07 14:08:35 pdelaney Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    NO WARRANTY
+    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+    solely responsible for determining the appropriateness of using and
+    distributing the Program and assumes all risks associated with its
+    exercise of rights under this Agreement, including but not limited to
+    the risks and costs of program errors, damage to or loss of data,
+    programs or equipment, and unavailability or interruption of operations.
+
+    DISCLAIMER OF LIABILITY
+    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef SCSIHOST_H_INCLUDED
+#define SCSIHOST_H_INCLUDED
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include <xeno/tqueue.h>
+#include <xeno/version.h>
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     SCSI Public stuff...
+ */
+
+/*
+ *     Try to keep these at 2^N-1
+ */
+#define MPT_FC_CAN_QUEUE       127
+#if defined MPT_SCSI_USE_NEW_EH
+       #define MPT_SCSI_CAN_QUEUE      127
+#else
+       #define MPT_SCSI_CAN_QUEUE      63
+#endif
+
+#define MPT_SCSI_CMD_PER_DEV_HIGH      31
+#define MPT_SCSI_CMD_PER_DEV_LOW       7
+
+#define MPT_SCSI_CMD_PER_LUN           7
+
+#define MPT_SCSI_MAX_SECTORS    8192
+
+/*
+ * Set the MAX_SGE value based on user input.
+ */
+#ifdef  CONFIG_FUSION_MAX_SGE
+#if     CONFIG_FUSION_MAX_SGE  < 16
+#define MPT_SCSI_SG_DEPTH      16
+#elif   CONFIG_FUSION_MAX_SGE  > 128
+#define MPT_SCSI_SG_DEPTH      128
+#else
+#define MPT_SCSI_SG_DEPTH      CONFIG_FUSION_MAX_SGE
+#endif
+#else
+#define MPT_SCSI_SG_DEPTH      40
+#endif
+
+/* To disable domain validation, uncomment the
+ * following line. No effect for FC devices.
+ * For SCSI devices, driver will negotiate to
+ * NVRAM settings (if available) or to maximum adapter
+ * capabilities.
+ */
+/* #define MPTSCSIH_DISABLE_DOMAIN_VALIDATION */
+
+
+/* SCSI driver setup structure. Settings can be overridden
+ * by command line options.
+ */
+#define MPTSCSIH_DOMAIN_VALIDATION      1
+#define MPTSCSIH_MAX_WIDTH              1
+#define MPTSCSIH_MIN_SYNC               0x08
+
+struct mptscsih_driver_setup
+{
+        u8      dv;
+        u8      max_width;
+        u8      min_sync_fac;
+};
+
+
+#define MPTSCSIH_DRIVER_SETUP                   \
+{                                               \
+        MPTSCSIH_DOMAIN_VALIDATION,             \
+        MPTSCSIH_MAX_WIDTH,                     \
+        MPTSCSIH_MIN_SYNC,                      \
+}
+
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     Various bits and pieces broke within the lk-2.4.0-testN series:-(
+ *     So here are various HACKS to work around them.
+ */
+
+/*
+ *     Conditionalizing with "#ifdef MODULE/#endif" around:
+ *             static Scsi_Host_Template driver_template = XX;
+ *             #include <../../scsi/scsi_module.c>
+ *     lines was REMOVED @ lk-2.4.0-test9
+ *     Issue discovered 20001213 by: sshirron
+ */
+#define MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS                   1
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0)
+#      if LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0)
+               /*
+                *      Super HACK!  -by sralston:-(
+                *      (good grief; heaven help me!)
+                */
+#              include <linux/capability.h>
+#              if !defined(CAP_LEASE) && !defined(MODULE)
+#                      undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+#              endif
+#      else
+#              ifndef MODULE
+#                      undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
+#              endif
+#      endif
+#endif
+
+/*
+ *     tq_scheduler disappeared @ lk-2.4.0-test12
+ *     (right when <linux/sched.h> newly defined TQ_ACTIVE)
+ *     tq_struct reworked in 2.5.41. Include workqueue.h.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#      include <linux/sched.h>
+#      include <linux/workqueue.h>
+#define SCHEDULE_TASK(x)               \
+       if (schedule_work(x) == 0) {    \
+               /*MOD_DEC_USE_COUNT*/;  \
+       }
+#else
+#define HAVE_TQ_SCHED  1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#      include <linux/sched.h>
+#      ifdef TQ_ACTIVE
+#              undef HAVE_TQ_SCHED
+#      endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+#              undef HAVE_TQ_SCHED
+#endif
+#endif
+#ifdef HAVE_TQ_SCHED
+#define SCHEDULE_TASK(x)               \
+       /*MOD_INC_USE_COUNT*/;          \
+       (x)->next = NULL;               \
+       queue_task(x, &tq_scheduler)
+#else
+
+/* SAE: mdelay */
+#define SCHEDULE_TASK(x) mdelay(100)
+
+#if XENO_KILLED
+
+#define SCHEDULE_TASK(x)               \
+       *MOD_INC_USE_COUNT*;            \
+       if (schedule_task(x) == 0) {    \
+               *MOD_DEC_USE_COUNT*;    
+
+#endif
+       
+#endif
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#define x_scsi_detect          mptscsih_detect
+#define x_scsi_release         mptscsih_release
+#define x_scsi_info            mptscsih_info
+#define x_scsi_queuecommand    mptscsih_qcmd
+#define x_scsi_abort           mptscsih_abort
+#define x_scsi_bus_reset       mptscsih_bus_reset
+#define x_scsi_dev_reset       mptscsih_dev_reset
+#define x_scsi_host_reset      mptscsih_host_reset
+#define x_scsi_bios_param      mptscsih_bios_param
+
+#define x_scsi_taskmgmt_bh     mptscsih_taskmgmt_bh
+#define x_scsi_old_abort       mptscsih_old_abort
+#define x_scsi_old_reset       mptscsih_old_reset
+#define x_scsi_select_queue_depths     mptscsih_select_queue_depths
+
+/* SAE: No proc */
+
+#if defined(CONFIG_PROC_FS)
+#define x_scsi_proc_info       mptscsih_proc_info
+#else
+#define x_scsi_proc_info       NULL
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *     MPT SCSI Host / Initiator decls...
+ */
+extern int              x_scsi_detect(Scsi_Host_Template *);
+extern int              x_scsi_release(struct Scsi_Host *host);
+extern const char      *x_scsi_info(struct Scsi_Host *);
+extern int              x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+#ifdef MPT_SCSI_USE_NEW_EH
+extern int              x_scsi_abort(Scsi_Cmnd *);
+extern int              x_scsi_bus_reset(Scsi_Cmnd *);
+extern int              x_scsi_dev_reset(Scsi_Cmnd *);
+extern int              x_scsi_host_reset(Scsi_Cmnd *);
+#else
+extern int              x_scsi_old_abort(Scsi_Cmnd *);
+extern int              x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
+#endif
+extern int              x_scsi_bios_param(Disk *, kdev_t, int *);
+extern void             x_scsi_taskmgmt_bh(void *);
+extern void             x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
+
+/* SAE: No proc */
+
+#if defined(CONFIG_PROC_FS)
+
+extern int              x_scsi_proc_info(char *, char **, off_t, int, int, int);
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define PROC_SCSI_DECL
+#else
+#define PROC_SCSI_DECL  .proc_name = "mptscsih",
+#endif
+
+#ifdef MPT_SCSI_USE_NEW_EH
+#define MPT_SCSIHOST {                                         \
+       .next                           = NULL,                 \
+       PROC_SCSI_DECL                                          \
+       .proc_info                      = x_scsi_proc_info,     \
+       .name                           = "MPT SCSI Host",      \
+       .detect                         = x_scsi_detect,        \
+       .release                        = x_scsi_release,       \
+       .info                           = x_scsi_info,          \
+       .command                        = NULL,                 \
+       .queuecommand                   = x_scsi_queuecommand,  \
+       .eh_strategy_handler            = NULL,                 \
+       .eh_abort_handler               = x_scsi_abort,         \
+       .eh_device_reset_handler        = x_scsi_dev_reset,     \
+       .eh_bus_reset_handler           = x_scsi_bus_reset,     \
+       .eh_host_reset_handler          = NULL,                 \
+       .bios_param                     = x_scsi_bios_param,    \
+       .can_queue                      = MPT_SCSI_CAN_QUEUE,   \
+       .this_id                        = -1,                   \
+       .sg_tablesize                   = MPT_SCSI_SG_DEPTH,    \
+       .cmd_per_lun                    = MPT_SCSI_CMD_PER_LUN, \
+       .unchecked_isa_dma              = 0,                    \
+       .use_clustering                 = ENABLE_CLUSTERING,    \
+       .use_new_eh_code                = 1                     \
+}
+
+#else /* MPT_SCSI_USE_NEW_EH */
+
+#define MPT_SCSIHOST {                                         \
+       .next                           = NULL,                 \
+       PROC_SCSI_DECL                                          \
+       .name                           = "MPT SCSI Host",      \
+       .detect                         = x_scsi_detect,        \
+       .release                        = x_scsi_release,       \
+       .info                           = x_scsi_info,          \
+       .command                        = NULL,                 \
+       .queuecommand                   = x_scsi_queuecommand,  \
+       .abort                          = x_scsi_old_abort,     \
+       .reset                          = x_scsi_old_reset,     \
+       .bios_param                     = x_scsi_bios_param,    \
+       .can_queue                      = MPT_SCSI_CAN_QUEUE,   \
+       .this_id                        = -1,                   \
+       .sg_tablesize                   = MPT_SCSI_SG_DEPTH,    \
+       .cmd_per_lun                    = MPT_SCSI_CMD_PER_LUN, \
+       .unchecked_isa_dma              = 0,                    \
+       .use_clustering                 = ENABLE_CLUSTERING     \
+}
+#endif  /* MPT_SCSI_USE_NEW_EH */
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*  include/scsi/scsi.h may not be quite complete...  */
+#ifndef RESERVE_10
+#define RESERVE_10             0x56
+#endif
+#ifndef RELEASE_10
+#define RELEASE_10             0x57
+#endif
+#ifndef PERSISTENT_RESERVE_IN
+#define PERSISTENT_RESERVE_IN  0x5e
+#endif
+#ifndef PERSISTENT_RESERVE_OUT
+#define PERSISTENT_RESERVE_OUT 0x5f
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#endif
+
diff --git a/xen/drivers/message/fusion/scsi3.h b/xen/drivers/message/fusion/scsi3.h
new file mode 100644 (file)
index 0000000..9160ba5
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ *  linux/drivers/message/fusion/scsi3.h
+ *      SCSI-3 definitions and macros.
+ *      (Ultimately) SCSI-3 definitions; for now, inheriting
+ *      SCSI-2 definitions.
+ *
+ *  Copyright (c) 1996-2002 Steven J. Ralston
+ *  Written By: Steven J. Ralston (19960517)
+ *  (mailto:sjralston1@netscape.net)
+ *  (mailto:lstephens@lsil.com)
+ *
+ *  $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $
+ */
+
+#ifndef SCSI3_H_INCLUDED
+#define SCSI3_H_INCLUDED
+/***************************************************************************/
+
+/****************************************************************************
+ *
+ *  Includes
+ */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+    #ifndef U_STUFF_DEFINED
+    #define U_STUFF_DEFINED
+    typedef unsigned char u8;
+    typedef unsigned short u16;
+    typedef unsigned int u32;
+    #endif
+#endif
+
+/****************************************************************************
+ *
+ *  Defines
+ */
+
+/*
+ *    SCSI Commands
+ */
+#define CMD_TestUnitReady      0x00
+#define CMD_RezeroUnit         0x01  /* direct-access devices */
+#define CMD_Rewind             0x01  /* sequential-access devices */
+#define CMD_RequestSense       0x03
+#define CMD_FormatUnit         0x04
+#define CMD_ReassignBlock      0x07
+#define CMD_Read6              0x08
+#define CMD_Write6             0x0A
+#define CMD_WriteFilemark      0x10
+#define CMD_Space              0x11
+#define CMD_Inquiry            0x12
+#define CMD_ModeSelect6        0x15
+#define CMD_ModeSense6         0x1A
+#define CMD_Reserve6           0x16
+#define CMD_Release6           0x17
+#define CMD_Erase              0x19
+#define CMD_StartStopUnit      0x1b  /* direct-access devices */
+#define CMD_LoadUnload         0x1b  /* sequential-access devices */
+#define CMD_ReceiveDiagnostic  0x1C
+#define CMD_SendDiagnostic     0x1D
+#define CMD_ReadCapacity       0x25
+#define CMD_Read10             0x28
+#define CMD_Write10            0x2A
+#define CMD_WriteVerify        0x2E
+#define CMD_Verify             0x2F
+#define CMD_SynchronizeCache   0x35
+#define CMD_ReadDefectData     0x37
+#define CMD_WriteBuffer        0x3B
+#define CMD_ReadBuffer         0x3C
+#define CMD_ReadLong           0x3E
+#define CMD_LogSelect          0x4C
+#define CMD_LogSense           0x4D
+#define CMD_ModeSelect10       0x55
+#define CMD_Reserve10          0x56
+#define CMD_Release10          0x57
+#define CMD_ModeSense10        0x5A
+#define CMD_PersistReserveIn   0x5E
+#define CMD_PersistReserveOut  0x5F
+#define CMD_ReportLuns         0xA0
+
+/*
+ *    Control byte field
+ */
+#define CONTROL_BYTE_NACA_BIT  0x04
+#define CONTROL_BYTE_Flag_BIT  0x02
+#define CONTROL_BYTE_Link_BIT  0x01
+
+/*
+ *    SCSI Messages
+ */
+#define MSG_COMPLETE             0x00
+#define MSG_EXTENDED             0x01
+#define MSG_SAVE_POINTERS        0x02
+#define MSG_RESTORE_POINTERS     0x03
+#define MSG_DISCONNECT           0x04
+#define MSG_IDERROR              0x05
+#define MSG_ABORT                0x06
+#define MSG_REJECT               0x07
+#define MSG_NOP                  0x08
+#define MSG_PARITY_ERROR         0x09
+#define MSG_LINKED_CMD_COMPLETE  0x0a
+#define MSG_LCMD_COMPLETE_W_FLG  0x0b
+#define MSG_BUS_DEVICE_RESET     0x0c
+#define MSG_ABORT_TAG            0x0d
+#define MSG_CLEAR_QUEUE          0x0e
+#define MSG_INITIATE_RECOVERY    0x0f
+
+#define MSG_RELEASE_RECOVRY      0x10
+#define MSG_TERMINATE_IO         0x11
+
+#define MSG_SIMPLE_QUEUE         0x20
+#define MSG_HEAD_OF_QUEUE        0x21
+#define MSG_ORDERED_QUEUE        0x22
+#define MSG_IGNORE_WIDE_RESIDUE  0x23
+
+#define MSG_IDENTIFY             0x80
+#define MSG_IDENTIFY_W_DISC      0xc0
+
+/*
+ *    SCSI Phases
+ */
+#define PHS_DATA_OUT  0x00
+#define PHS_DATA_IN   0x01
+#define PHS_COMMAND   0x02
+#define PHS_STATUS    0x03
+#define PHS_MSG_OUT   0x06
+#define PHS_MSG_IN    0x07
+
+/*
+ *    Statuses
+ */
+#define STS_GOOD                        0x00
+#define STS_CHECK_CONDITION             0x02
+#define STS_CONDITION_MET               0x04
+#define STS_BUSY                        0x08
+#define STS_INTERMEDIATE                0x10
+#define STS_INTERMEDIATE_CONDITION_MET  0x14
+#define STS_RESERVATION_CONFLICT        0x18
+#define STS_COMMAND_TERMINATED          0x22
+#define STS_TASK_SET_FULL               0x28
+#define    STS_QUEUE_FULL               0x28
+#define STS_ACA_ACTIVE                  0x30
+
+#define STS_VALID_MASK                  0x3e
+
+#define SCSI_STATUS(x)  ((x) & STS_VALID_MASK)
+
+/*
+ *    SCSI QTag Types
+ */
+#define QTAG_SIMPLE     0x20
+#define QTAG_HEAD_OF_Q  0x21
+#define QTAG_ORDERED    0x22
+
+/*
+ *    SCSI Sense Key Definitons
+ */
+#define SK_NO_SENSE         0x00
+#define SK_RECOVERED_ERROR  0x01
+#define SK_NOT_READY        0x02
+#define SK_MEDIUM_ERROR     0x03
+#define SK_HARDWARE_ERROR   0x04
+#define SK_ILLEGAL_REQUEST  0x05
+#define SK_UNIT_ATTENTION   0x06
+#define SK_DATA_PROTECT     0x07
+#define SK_BLANK_CHECK      0x08
+#define SK_VENDOR_SPECIFIC  0x09
+#define SK_COPY_ABORTED     0x0a
+#define SK_ABORTED_COMMAND  0x0b
+#define SK_EQUAL            0x0c
+#define SK_VOLUME_OVERFLOW  0x0d
+#define SK_MISCOMPARE       0x0e
+#define SK_RESERVED         0x0f
+
+
+
+#define SCSI_MAX_INQUIRY_BYTES  96
+#define SCSI_STD_INQUIRY_BYTES  36
+
+#undef USE_SCSI_COMPLETE_INQDATA
+/*
+ *      Structure definition for SCSI Inquiry Data
+ *
+ *  NOTE: The following structure is 96 bytes in size
+ *      iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 36 bytes in size.
+ *  THE CHOICE IS YOURS!
+ */
+typedef struct SCSI_Inquiry_Data
+{
+#ifdef USE_SCSI_COMPLETE_INQDATA
+    u8   InqByte[SCSI_MAX_INQUIRY_BYTES];
+#else
+    u8   InqByte[SCSI_STD_INQUIRY_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+        u32    Periph_Device_Type    : 5,
+               Periph_Qualifier      : 3,
+               Device_Type_Modifier  : 7,
+               Removable_Media       : 1,
+               ANSI_Version          : 3,
+               ECMA_Version          : 3,
+               ISO_Version           : 2,
+               Response_Data_Format  : 4,
+               reserved_0            : 3,
+               AERC                  : 1  ;
+        u32    Additional_Length     : 8,
+               reserved_1            :16,
+               SftReset              : 1,
+               CmdQue                : 1,
+               reserved_2            : 1,
+               Linked                : 1,
+               Sync                  : 1,
+               WBus16                : 1,
+               WBus32                : 1,
+               RelAdr                : 1  ;
+        u8     Vendor_ID[8];
+        u8     Product_ID[16];
+        u8     Revision_Level [4];
+#ifdef USE_SCSI_COMPLETE_INQDATA
+        u8     Vendor_Specific[20];
+        u8     reserved_3[40];
+#endif
+ *
+ */
+
+} SCSI_Inquiry_Data_t;
+
+#define INQ_PERIPHINFO_BYTE            0
+#define   INQ_Periph_Qualifier_MASK      0xe0
+#define   INQ_Periph_Device_Type_MASK    0x1f
+
+#define INQ_Peripheral_Qualifier(inqp) \
+    (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5)
+#define INQ_Peripheral_Device_Type(inqp) \
+    (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK)
+
+
+#define INQ_DEVTYPEMOD_BYTE            1
+#define   INQ_RMB_BIT                    0x80
+#define   INQ_Device_Type_Modifier_MASK  0x7f
+
+#define INQ_Removable_Medium(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT)
+#define INQ_Device_Type_Modifier(inqp) \
+    (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK)
+
+
+#define INQ_VERSIONINFO_BYTE           2
+#define   INQ_ISO_Version_MASK           0xc0
+#define   INQ_ECMA_Version_MASK          0x38
+#define   INQ_ANSI_Version_MASK          0x07
+
+#define INQ_ISO_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK)
+#define INQ_ECMA_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK)
+#define INQ_ANSI_Version(inqp) \
+    (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK)
+
+
+#define INQ_BYTE3                      3
+#define   INQ_AERC_BIT                   0x80
+#define   INQ_TrmTsk_BIT                 0x40
+#define   INQ_NormACA_BIT                0x20
+#define   INQ_RDF_MASK                   0x0F
+
+#define INQ_AER_Capable(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT)
+#define INQ_TrmTsk(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT)
+#define INQ_NormACA(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT)
+#define INQ_Response_Data_Format(inqp) \
+    (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK)
+
+
+#define INQ_CAPABILITY_BYTE            7
+#define   INQ_RelAdr_BIT                 0x80
+#define   INQ_WBus32_BIT                 0x40
+#define   INQ_WBus16_BIT                 0x20
+#define   INQ_Sync_BIT                   0x10
+#define   INQ_Linked_BIT                 0x08
+  /*      INQ_Reserved BIT               0x40 */
+#define   INQ_CmdQue_BIT                 0x02
+#define   INQ_SftRe_BIT                  0x01
+
+#define IS_RelAdr_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT)
+#define IS_WBus32_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT)
+#define IS_WBus16_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT)
+#define IS_Sync_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT)
+#define IS_Linked_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT)
+#define IS_CmdQue_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT)
+#define IS_SftRe_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT)
+
+#define INQ_Width_BITS \
+    (INQ_WBus32_BIT | INQ_WBus16_BIT)
+#define IS_Wide_DEV(inqp) \
+    (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS)
+
+
+/*
+ *      SCSI peripheral device types
+ */
+#define SCSI_TYPE_DAD               0x00  /* Direct Access Device */
+#define SCSI_TYPE_SAD               0x01  /* Sequential Access Device */
+#define SCSI_TYPE_TAPE  SCSI_TYPE_SAD
+#define SCSI_TYPE_PRT               0x02  /* Printer */
+#define SCSI_TYPE_PROC              0x03  /* Processor */
+#define SCSI_TYPE_WORM              0x04
+#define SCSI_TYPE_CDROM             0x05
+#define SCSI_TYPE_SCAN              0x06  /* Scanner */
+#define SCSI_TYPE_OPTICAL           0x07  /* Magneto/Optical */
+#define SCSI_TYPE_CHANGER           0x08
+#define SCSI_TYPE_COMM              0x09  /* Communications device */
+#define SCSI_TYPE_UNKNOWN           0x1f
+#define SCSI_TYPE_UNCONFIGURED_LUN  0x7f
+
+#define SCSI_TYPE_MAX_KNOWN         SCSI_TYPE_COMM
+
+/*
+ *      Peripheral Qualifiers
+ */
+#define DEVICE_PRESENT     0x00
+#define LUN_NOT_PRESENT    0x01
+#define LUN_NOT_SUPPORTED  0x03
+
+/*
+ *      ANSI Versions
+ */
+#ifndef SCSI_1
+#define SCSI_1  0x01
+#endif
+#ifndef SCSI_2
+#define SCSI_2  0x02
+#endif
+#ifndef SCSI_3
+#define SCSI_3  0x03
+#endif
+
+
+#define SCSI_MAX_SENSE_BYTES  255
+#define SCSI_STD_SENSE_BYTES   18
+#define SCSI_PAD_SENSE_BYTES      (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES)
+
+#undef USE_SCSI_COMPLETE_SENSE
+/*
+ *      Structure definition for SCSI Sense Data
+ *
+ *  NOTE: The following structure is 255 bytes in size
+ *      iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define").
+ *      If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef")
+ *      then the following structure is only 19 bytes in size.
+ *  THE CHOICE IS YOURS!
+ *
+ */
+typedef struct SCSI_Sense_Data
+{
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8       SenseByte[SCSI_MAX_SENSE_BYTES];
+#else
+    u8       SenseByte[SCSI_STD_SENSE_BYTES];
+#endif
+
+/*
+ * the following structure works only for little-endian (Intel,
+ * LSB first (1234) byte order) systems with 4-byte ints.
+ *
+    u8     Error_Code                :4,            // 0x00
+           Error_Class               :3,
+           Valid                     :1
+     ;
+    u8     Segment_Number                           // 0x01
+     ;
+    u8     Sense_Key                 :4,            // 0x02
+           Reserved                  :1,
+           Incorrect_Length_Indicator:1,
+           End_Of_Media              :1,
+           Filemark                  :1
+     ;
+    u8     Information_MSB;                         // 0x03
+    u8     Information_Byte2;                       // 0x04
+    u8     Information_Byte1;                       // 0x05
+    u8     Information_LSB;                         // 0x06
+    u8     Additional_Length;                       // 0x07
+
+    u32    Command_Specific_Information;            // 0x08 - 0x0b
+
+    u8     Additional_Sense_Code;                   // 0x0c
+    u8     Additional_Sense_Code_Qualifier;         // 0x0d
+    u8     Field_Replaceable_Unit_Code;             // 0x0e
+    u8     Illegal_Req_Bit_Pointer   :3,            // 0x0f
+           Illegal_Req_Bit_Valid     :1,
+           Illegal_Req_Reserved      :2,
+           Illegal_Req_Cmd_Data      :1,
+           Sense_Key_Specific_Valid  :1
+     ;
+    u16    Sense_Key_Specific_Data;                 // 0x10 - 0x11
+
+#ifdef USE_SCSI_COMPLETE_SENSE
+    u8     Additional_Sense_Data[SCSI_PAD_SENSE_BYTES];
+#else
+    u8     Additional_Sense_Data[1];
+#endif
+ *
+ */
+
+} SCSI_Sense_Data_t;
+
+
+#define SD_ERRCODE_BYTE                0
+#define   SD_Valid_BIT                   0x80
+#define   SD_Error_Code_MASK             0x7f
+#define SD_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT)
+#define SD_Error_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK)
+
+
+#define SD_SEGNUM_BYTE                 1
+#define SD_Segment_Number(sdp)  (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE))
+
+
+#define SD_SENSEKEY_BYTE               2
+#define   SD_Filemark_BIT                0x80
+#define   SD_EOM_BIT                     0x40
+#define   SD_ILI_BIT                     0x20
+#define   SD_Sense_Key_MASK              0x0f
+#define SD_Filemark(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT)
+#define SD_EOM(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT)
+#define SD_ILI(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT)
+#define SD_Sense_Key(sdp) \
+    (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK)
+
+
+#define SD_INFO3_BYTE                  3
+#define SD_INFO2_BYTE                  4
+#define SD_INFO1_BYTE                  5
+#define SD_INFO0_BYTE                  6
+#define SD_Information3(sdp)  (int)(*((u8*)(sdp)+SD_INFO3_BYTE))
+#define SD_Information2(sdp)  (int)(*((u8*)(sdp)+SD_INFO2_BYTE))
+#define SD_Information1(sdp)  (int)(*((u8*)(sdp)+SD_INFO1_BYTE))
+#define SD_Information0(sdp)  (int)(*((u8*)(sdp)+SD_INFO0_BYTE))
+
+
+#define SD_ADDL_LEN_BYTE               7
+#define SD_Additional_Sense_Length(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE))
+#define SD_Addl_Sense_Len  SD_Additional_Sense_Length
+
+
+#define SD_CMD_SPECIFIC3_BYTE          8
+#define SD_CMD_SPECIFIC2_BYTE          9
+#define SD_CMD_SPECIFIC1_BYTE         10
+#define SD_CMD_SPECIFIC0_BYTE         11
+#define SD_Cmd_Specific_Info3(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE))
+#define SD_Cmd_Specific_Info2(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE))
+#define SD_Cmd_Specific_Info1(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE))
+#define SD_Cmd_Specific_Info0(sdp)  (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE))
+
+
+#define SD_ADDL_SENSE_CODE_BYTE       12
+#define SD_Additional_Sense_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE))
+#define SD_Addl_Sense_Code  SD_Additional_Sense_Code
+#define SD_ASC  SD_Additional_Sense_Code
+
+
+#define SD_ADDL_SENSE_CODE_QUAL_BYTE  13
+#define SD_Additional_Sense_Code_Qualifier(sdp) \
+    (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE))
+#define SD_Addl_Sense_Code_Qual  SD_Additional_Sense_Code_Qualifier
+#define SD_ASCQ  SD_Additional_Sense_Code_Qualifier
+
+
+#define SD_FIELD_REPL_UNIT_CODE_BYTE  14
+#define SD_Field_Replaceable_Unit_Code(sdp) \
+    (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE))
+#define SD_Field_Repl_Unit_Code  SD_Field_Replaceable_Unit_Code
+#define SD_FRUC  SD_Field_Replaceable_Unit_Code
+#define SD_FRU  SD_Field_Replaceable_Unit_Code
+
+
+/*
+ *  Sense-Key Specific offsets and macros.
+ */
+#define SD_SKS2_BYTE                  15
+#define   SD_SKS_Valid_BIT               0x80
+#define   SD_SKS_Cmd_Data_BIT            0x40
+#define   SD_SKS_Bit_Ptr_Valid_BIT       0x08
+#define   SD_SKS_Bit_Ptr_MASK            0x07
+#define SD_SKS1_BYTE                  16
+#define SD_SKS0_BYTE                  17
+#define SD_Sense_Key_Specific_Valid(sdp) \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT)
+#define SD_SKS_Valid  SD_Sense_Key_Specific_Valid
+#define SD_SKS_CDB_Error(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT)
+#define SD_Was_Illegal_Request  SD_SKS_CDB_Error
+#define SD_SKS_Bit_Pointer_Valid(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT)
+#define SD_SKS_Bit_Pointer(sdp)  \
+    (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK)
+#define SD_Field_Pointer(sdp)  \
+    (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \
+      + *((u8*)(sdp)+SD_SKS0_BYTE) )
+#define SD_Bad_Byte  SD_Field_Pointer
+#define SD_Actual_Retry_Count  SD_Field_Pointer
+#define SD_Progress_Indication  SD_Field_Pointer
+
+/*
+ *  Mode Sense Write Protect Mask
+ */
+#define WRITE_PROTECT_MASK      0X80
+
+/*
+ *  Medium Type Codes
+ */
+#define OPTICAL_DEFAULT                 0x00
+#define OPTICAL_READ_ONLY_MEDIUM        0x01
+#define OPTICAL_WRITE_ONCE_MEDIUM       0x02
+#define OPTICAL_READ_WRITABLE_MEDIUM    0x03
+#define OPTICAL_RO_OR_WO_MEDIUM         0x04
+#define OPTICAL_RO_OR_RW_MEDIUM         0x05
+#define OPTICAL_WO_OR_RW_MEDIUM         0x06
+
+
+
+/*
+ *    Structure definition for READ6, WRITE6 (6-byte CDB)
+ */
+typedef struct SCSI_RW6_CDB
+{
+    u32    OpCode      :8,
+           LBA_HI      :5,    /* 5 MSBit's of the LBA */
+           Lun         :3,
+           LBA_MID     :8,    /* NOTE: total of 21 bits in LBA */
+           LBA_LO      :8  ;  /* Max LBA = 0x001fffff          */
+    u8     BlockCount;
+    u8     Control;
+} SCSI_RW6_t;
+
+#define MAX_RW6_LBA  ((u32)0x001fffff)
+
+/*
+ *  Structure definition for READ10, WRITE10 (10-byte CDB)
+ *
+ *    NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for
+ *    the ADP-92 DAC only.  In the SCSI2 spec. this same bit is defined as a
+ *    FUA (forced unit access) bit for READs and WRITEs.  Since this driver
+ *    does not use the FUA, this bit is defined as it is used by the ADP-92.
+ *    Also, for READ CAPACITY, only the OpCode field is used.
+ */
+typedef struct SCSI_RW10_CDB
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u32    LBA;
+    u8     Reserved2;
+    u16    BlockCount;
+    u8     Control;
+} SCSI_RW10_t;
+
+#define PARITY_CHECK  0x08    /* parity check bit - byte[1], bit 3 */
+
+    /*
+     *  Structure definition for data returned by READ CAPACITY cmd;
+     *  READ CAPACITY data
+     */
+    typedef struct READ_CAP_DATA
+    {
+        u32    MaxLBA;
+        u32    BlockBytes;
+    } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t;
+
+
+/*
+ *  Structure definition for FORMAT UNIT CDB (6-byte CDB)
+ */
+typedef struct _SCSI_FORMAT_UNIT
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     VendorSpecific;
+    u16    Interleave;
+    u8     Control;
+} SCSI_FORMAT_UNIT_t;
+
+/*
+ *    Structure definition for REQUEST SENSE (6-byte CDB)
+ */
+typedef struct _SCSI_REQUEST_SENSE
+{
+    u8     OpCode;
+    u8     Reserved1;
+    u8     Reserved2;
+    u8     Reserved3;
+    u8     AllocLength;
+    u8     Control;
+} SCSI_REQ_SENSE_t;
+
+/*
+ *  Structure definition for REPORT LUNS (12-byte CDB)
+ */
+typedef struct _SCSI_REPORT_LUNS
+{
+    u8     OpCode;
+    u8     Reserved1[5];
+    u32    AllocationLength;
+    u8     Reserved2;
+    u8     Control;
+} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t;
+
+    /*
+     *  (per-level) LUN information bytes
+     */
+/*
+ *  Following doesn't work on ARMCC compiler
+ *  [apparently] because it pads every struct
+ *  to be multiple of 4 bytes!
+ *  So SCSI_LUN_LEVELS_t winds up being 16
+ *  bytes instead of 8!
+ *
+    typedef struct LUN_INFO
+    {
+        u8     AddrMethod_plus_LunOrBusNumber;
+        u8     LunOrTarget;
+    } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t;
+
+    typedef struct LUN_LEVELS
+    {
+        SCSI_LUN_INFO_t  LUN_0;
+        SCSI_LUN_INFO_t  LUN_1;
+        SCSI_LUN_INFO_t  LUN_2;
+        SCSI_LUN_INFO_t  LUN_3;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+*/
+    /*
+     *  All 4 levels (8 bytes) of LUN information
+     */
+    typedef struct LUN_LEVELS
+    {
+        u8     LVL1_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL1_LunOrTarget;
+        u8     LVL2_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL2_LunOrTarget;
+        u8     LVL3_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL3_LunOrTarget;
+        u8     LVL4_AddrMethod_plus_LunOrBusNumber;
+        u8     LVL4_LunOrTarget;
+    } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t;
+
+    /*
+     *  Structure definition for data returned by REPORT LUNS cmd;
+     *  LUN reporting parameter list format
+     */
+    typedef struct LUN_REPORT
+    {
+        u32                LunListLength;
+        u32                Reserved;
+        SCSI_LUN_LEVELS_t  LunInfo[1];
+    } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t;
+
+/****************************************************************************
+ *
+ *  Externals
+ */
+
+/****************************************************************************
+ *
+ *  Public Typedefs & Related Defines
+ */
+
+/****************************************************************************
+ *
+ *  Macros (embedded, above)
+ */
+
+/****************************************************************************
+ *
+ *  Public Variables
+ */
+
+/****************************************************************************
+ *
+ *  Public Prototypes (module entry points)
+ */
+
+
+/***************************************************************************/
+#endif
index 13b0aded8a8af44652dbb9a062f1a487325a8349..44e9aa59f6b1f4f69d8824f85737943f2d8955fb 100644 (file)
@@ -3355,8 +3355,6 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
                skip_id = (skip_id > 15) ? -1 : skip_id;
        }
 
-       printk (KERN_NOTICE "megaraid: " MEGARAID_VERSION);
-
        memset (mega_hbas, 0, sizeof (mega_hbas));
 
        /* Detect ROMBs first */
@@ -3378,7 +3376,11 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
        count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_QC_VERDE,
                                PCI_DEVICE_ID_PERC4_QC_VERDE, BOARD_QUARTZ);
 
-       mega_reorder_hosts ();
+       if (count)
+               printk (KERN_NOTICE "megaraid: " MEGARAID_VERSION);
+
+       if (count)
+               mega_reorder_hosts ();
 
 #ifdef CONFIG_PROC_FS
        if (count) {